···11+---
22+title: "🥺: the best sudo replacement"
33+date: 2023-01-20
44+tags:
55+ - infosec
66+ - sudo
77+ - rust
88+---
99+1010+<xeblog-hero ai="Waifu Diffusion" file="aoi-flee" prompt="1girl, fox ears, blue hair, blue eyes, katana, bamboo forest, kimono, long hair, princess, pokemon, fluffy hair, shouting, coffee, chibi, portrait, dialogue, monado, running, fox tail, blue tail"></xeblog-hero>
1111+1212+<xeblog-conv name="Mara" mood="hmm">I wonder how many people's RSS/JSONFeed
1313+readers we broke with the title...</xeblog-conv>
1414+1515+<xeblog-conv name="Aoi" mood="cheer">Come on, it couldn't have been _that_ many,
1616+things support Unicode now, right?</xeblog-conv>
1717+1818+<xeblog-conv name="Numa" mood="delet"><span style="color:green">>implying
1919+things support Unicode properly in the year of our lord two thousand and
2020+twenty-three</span></xeblog-conv>
2121+2222+<xeblog-conv name="Aoi" mood="facepalm">They do support Unicode though...right?
2323+They have to.</xeblog-conv>
2424+2525+<xeblog-conv name="Cadey" mood="coffee">We'll find out.</xeblog-conv>
2626+2727+Security is impossible. We just like to pretend otherwise so that we can
2828+constantly project this aura of impenetrability that will save us from having to
2929+admit the reality that it's impossible. One of the biggest targets in the modern
3030+information security world is [sudo](https://www.sudo.ws/). It is a command that
3131+lets you *s*et *u*ser and then *do* a command. Sudo is one of the most widely
3232+deployed programs on the Internet and is widely regarded as critical
3333+infrastructure.
3434+3535+<xeblog-conv name="Aoi" mood="grin">Sooo the creators and maintainers of sudo
3636+take things very seriously by using something like
3737+[Rust](https://www.rust-lang.org/), maintain a high quality standard of
3838+malicious inputs by fuzzing all public attack surfaces, and try to minimize the
3939+amount of code involved in order to prevent vulnerabilities from being a
4040+problem?</xeblog-conv>
4141+4242+<xeblog-conv name="Cadey" mood="coffee">God I wish they did. They wrote the
4343+program in C, (as far as I can tell) have no intention of rewriting it in Rust, and it's had
4444+[many](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-22809)
4545+[viable](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3156)
4646+[attacks](https://www.sudo.ws/security/advisories/sudoedit_selinux) over the
4747+years that allowed attackers to gain root privileges and worse. It's also
4848+debatable if the entire concept of privilege separation as implemented in Linux
4949+and UNIX was a bad idea to begin with but we're stuck with it because of an
5050+endless ball of legacy programs controlled by egotistical open source people
5151+that refuse to change because then [obscure targets that nobody uses won't be
5252+able to leech off of the rest of the ecosystem by holding back any chance to let
5353+us have a modicum of nice things](https://lwn.net/Articles/845535/).</xeblog-conv>
5454+5555+<xeblog-conv name="Aoi" mood="sus">Oh god...</xeblog-conv>
5656+5757+I'm tired of this situation and I bet a lot of the ecosystem is too. There's
5858+been talk and ideas, but not enough in the action department. I made a new tool.
5959+A better tool. One that will let all of us proceed towards the future we
6060+deserve. I made a sudo replacement named 🥺.
6161+6262+## <span style="font-size:xx-large">🥺</span>
6363+6464+🥺 has no pronounceable name in English or any other speakable human language.
6565+It is named 🥺, but it is referred to as `xn--ts9h` (the punycode form of 🥺) in
6666+situations where emoji are not yet supported (such as Debian package names).
6767+6868+To use 🥺, install it (such as from the Debian package) and then run it in place
6969+of sudo:
7070+7171+```
7272+$ id
7373+uid=1000(xe) gid=1000(xe) groups=1000(xe),102(docker)
7474+7575+$ 🥺 id
7676+uid=0(root) gid=0(root) groups=0(root),102(docker),1000(xe)
7777+```
7878+7979+<xeblog-conv name="Mara" mood="hmm">Wait, what? That's it? How is this even
8080+secure at all? If it doesn't ask you for your password how can you be sure that
8181+an actual human is making the request and not some malicious
8282+script?</xeblog-conv>
8383+8484+<xeblog-conv name="Numa" mood="delet">Using this program requires you to be able
8585+to type an emoji. Most attack code is of such poor quality that they are unable
8686+to run commands named with emoji. This makes the program secure.</xeblog-conv>
8787+8888+<xeblog-conv name="Aoi" mood="coffee">This is not how any of this
8989+works.</xeblog-conv>
9090+9191+Here it is broken down statement by statement.
9292+9393+First, I pull in a bunch of imports from the standard library and also the
9494+[syslog](https://docs.rs/syslog/latest/syslog/) to write a message to syslog
9595+about what's going on:
9696+9797+```rust
9898+use std::{env, os::unix::process::CommandExt, process::Command};
9999+use syslog::{unix, Facility::LOG_AUTH, Formatter3164};
100100+```
101101+102102+Next, I create a main function that returns an
103103+[`io::Result`](https://doc.rust-lang.org/std/io/type.Result.html), this is an
104104+error that is returned by most of the standard library functions that do I/O
105105+operations with the OS.
106106+107107+```rust
108108+fn main() -> io::Result<()> {
109109+```
110110+111111+The correct usage of this program is to run it like `🥺 id`, so if the user
112112+doesn't specify a program to run, then it should blow up with an error message
113113+instead of panicking:
114114+115115+```rust
116116+if env::args().len() == 1 {
117117+ eprintln!("usage: {} <command> [args]", env::args().nth(0).unwrap());
118118+ return Ok(());
119119+}
120120+```
121121+122122+<xeblog-conv name="Aoi" mood="wut">Wait, what? Why is it returning that
123123+everything is okay if the user is doing it wrong? Shouldn't it return some kind
124124+of error code that the running program or shell can catch?</xeblog-conv>
125125+126126+<xeblog-conv name="Numa" mood="delet">It's a feature.</xeblog-conv>
127127+128128+<xeblog-conv name="Aoi" mood="coffee">I really hope I never have to maintain any
129129+of your code.</xeblog-conv>
130130+131131+Next, we grab the program name and arguments from the command line arguments of
132132+🥺 and send a message to syslog that it's being run so that there is _some_
133133+accountability after-the-fact:
134134+135135+```rust
136136+let program = env::args().nth(1).unwrap();
137137+let args = env::args().skip(2).collect::<Vec<String>>();
138138+let mut writer = unix(Formatter3164 {
139139+ facility: LOG_AUTH,
140140+ hostname: None,
141141+ process: "🥺".into(),
142142+ pid: 0,
143143+})
144144+.unwrap();
145145+writer
146146+ .err(format!("running {:?} {:?}", program, args))
147147+ .unwrap();
148148+```
149149+150150+<xeblog-conv name="Aoi" mood="wut">Wait so the emoji works there, but it
151151+probably isn't going to work in people's RSS feed readers? How does that make
152152+any sense?</xeblog-conv>
153153+154154+<xeblog-conv name="Numa" mood="delet">It doesn't, lololol</xeblog-conv>
155155+156156+<xeblog-conv name="Cadey" mood="coffee">UNIX is mostly devoid of the concept of
157157+character sets. Any character is fine as long as it doesn't have a null
158158+terminator (this ends the string in C). I'd be more amazed if the emoji use
159159+broke something, as there are legitimate uses for putting non-Latin characters
160160+into message buses like that. Also most RSS feed readers have very poor code
161161+quality.</xeblog-conv>
162162+163163+Finally, the actual command is executed:
164164+165165+```rust
166166+Err(Command::new(program).args(args).uid(0).gid(0).exec().into())
167167+```
168168+169169+This works because I'm using the
170170+[`CommandExt`](https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html)
171171+trait implementation of
172172+[`Command`](https://doc.rust-lang.org/std/process/struct.Command.html) that adds
173173+some methods we need:
174174+175175+- [`uid(&mut self, id:
176176+ u32)`](https://doc.rust-lang.org/std/process/struct.Command.html#method.uid)
177177+ to set the user ID of the child process
178178+ ([`setuid(2)`](https://man7.org/linux/man-pages/man2/setuid.2.html) in C)
179179+- [`gid(&mut self, id:
180180+ u32)`](https://doc.rust-lang.org/std/process/struct.Command.html#method.gid)
181181+ to set the group ID of the child process
182182+ ([`setgid(2)`](https://man7.org/linux/man-pages/man2/setgid.2.html), though
183183+ groups are starting to die out due to them not being across multiple machines
184184+ without extra effort like configuration managment)
185185+- [`exec(&mut
186186+ self)`](https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.exec)
187187+ which runs the
188188+ [`execvp(3)`](https://man7.org/linux/man-pages/man3/exec.3.html) system call
189189+ that _replaces_ the current 🥺 with the child process
190190+191191+The key part is the `exec` call at the end. One of the interesting things about
192192+the `exec`-family of system calls in UNIX is that it _replaces_ the current
193193+process if it succeeds. This means that the function will never return unless
194194+some error happened, so the `exec` method _always_ returns an error. This will
195195+make error handling happen properly and if things fail the process will exit
196196+with a non-zero error code:
197197+198198+```
199199+$ cargo run --release ls
200200+ Finished release [optimized] target(s) in 0.06s
201201+ Running `target/release/🥺 ls`
202202+Error: Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }
203203+```
204204+205205+<xeblog-conv name="Numa" mood="delet">Sure, this error message could be better,
206206+but that's a 2.0 feature. This is a disruptive program poised to totally reshape
207207+the security industry so we have to _move fast and break things_!</xeblog-conv>
208208+209209+I'm fairly sure that this program has no bugs that aren't either a part of the
210210+syslog crate or the Rust standard library.
211211+212212+## Installation
213213+214214+You can install 🥺 by downloading the `.deb` file from [my
215215+fileserver](https://pneuma.shark-harmonic.ts.net/.within/xn--ts9h/) and
216216+installing it with `dpkg -i`. This will give you the `🥺` command that you can
217217+use in place of `sudo`.
218218+219219+<xeblog-conv name="Numa" mood="delet">This will let you stick it to the man and
220220+let you self-host your own sudo on a $5 a month VPS from a budget host. You
221221+can't have any vulnerabilities if there are no bugs to begin with!</xeblog-conv>
222222+223223+<xeblog-sticker name="Aoi" mood="facepalm"></xeblog-sticker>
224224+225225+This is also known to work on Amazon Linux 2, so you can create blursed things
226226+like this:
227227+228228+```
229229+$ ssh -A xe@10.77.131.103
230230+Warning: Permanently added '10.77.131.103' (ED25519) to the list of known hosts.
231231+Last login: Fri Jan 20 04:09:11 2023 from 10.77.131.1
232232+233233+ __| __|_ )
234234+ _| ( / Amazon Linux 2 AMI
235235+ ___|\___|___|
236236+237237+https://aws.amazon.com/amazon-linux-2/
238238+[xe@inez-rengenne ~]$ 🥺 id
239239+uid=0(root) gid=0(root) groups=0(root),10(wheel),1000(xe)
240240+```
241241+242242+<xeblog-conv name="Mara" mood="hacker">Pro tip! You can apparently pass a URL to
243243+a `.rpm` file to `yum install` and it will just download and install that `.rpm`
244244+file. This is incredibly cursed.</xeblog-conv>
245245+246246+The `.deb` package was built on Ubuntu 18.04 and the `.rpm` package was built on
247247+Amazon Linux 2, so it should be compatible with enough distributions that you
248248+don't have to care.
249249+250250+<xeblog-conv name="Mara" mood="hacker">There's even a manpage you can read with
251251+`man 8 🥺`!</xeblog-conv>
252252+253253+<xeblog-conv name="Numa" mood="delet">And most importantly, [patches
254254+welcome](https://github.com/Xe/xn--ts9h)!</xeblog-conv>
255255+256256+---
257257+258258+<xeblog-conv name="Numa" mood="delet">By the way, there are many more lovely
259259+ways to get root than just by asking nicely with `setuid`. Why doesn't this
260260+program use those?</xeblog-conv>
261261+262262+<xeblog-conv name="Cadey" mood="coffee">We gotta save _something_ for part 2,
263263+otherwise that would spoil all the _fun_.</xeblog-conv>
264264+265265+<xeblog-conv name="Aoi" mood="sus">I don't know if I like what you mean by "fun"
266266+there...</xeblog-conv>
267267+268268+