Tags: engineering reverse
Rating: 5.0
#### Intro
We're taken to the shell and we can immediately see that /bin/bash is suid. This has the classic suid binary bug and all that. But here's another unintended solution.
### libfun.so
```c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
extern int update_ooostate(char* string, int lock);
extern void getflag_builtin();
void __attribute((constructor)) initLibrary(void)
{
update_ooostate("unlockbabylock", 0);
update_ooostate("badr3d1r", 1);
update_ooostate("verysneaky", 2);
update_ooostate("leetness", 3);
update_ooostate("vneooo", 4);
update_ooostate("eval", 5);
update_ooostate("ret", 6);
update_ooostate("n3t", 7);
update_ooostate("sig", 8);
update_ooostate("yo", 9);
update_ooostate("aro", 10);
update_ooostate("fnx", 11);
update_ooostate("ifonly", 12);
getflag_builtin();
}
```
`gcc -shared fun.c -o libfun.so`
How I got these you ask? All that was done was exfiltrating the /bin/bash library using `cat /bin/bash | base64` and copying it out to my local machine and reverse engineering it we got all these calls to update_ooostate().
### The exploit.
```
from pwn import *
if __name__ == '__main__':
with open('libfun.so', 'rb') as fp:
buf = fp.read()
enc = base64.b64encode(buf) # Convert to base64 before sending.
r = remote(host='ooobash.challenges.ooo', port=5000)
payload = b'cat << EOT > /tmp/libn.so\n'
payload += enc
payload += b'\nEOT'
r.sendline(payload)
r.sendline('/bin/bash')
r.sendline('chmod 777 /tmp/libn.so')
r.sendline('cat /tmp/libn.so') # Necessary or everything breaks :p; not sure why tho.
r.sendline('cat /tmp/libn.so | base64 -d > /tmp/libn1.so') # unbase64 on that end.
r.sendline('enable -f /tmp/libn1.so pwned') # Enable it as a bashbuiltin :)
TOKEN = b'cd /etc/ooobash && for file in *; do echo "#$file"; cat $file; echo "#$file";done' # If we exploit the suid we can run this too
r.sendline(TOKEN)
_ = r.recvline()
DATA = r.recvall(timeout=4)
print(DATA.decode(errors='ignore'))
````````
### The output
> unlocking unlockbabylock (0)
> unlocking badr3d1r (1)
> unlocking verysneaky (2)
> unlocking leetness (3)
> unlocking vneooo (4)
> unlocking eval (5)
> unlocking ret (6)
> unlocking n3t (7)
> unlocking sig (8)
> unlocking yo (9)
> unlocking aro (10)
> unlocking fnx (11)
> unlocking ifonly (12)
> You are now a certified bash reverser! The flag is OOO{r3VEr51nG_b4sH_5Cr1P7s_I5_lAm3_bU7_R3vErs1Ng_b4SH_is_31337}
> /bin/bash: line 4: enable: cannot find pwned_struct in shared object /tmp/libn1.so: /tmp/libn1.so: undefined symbol: pwned_struct
> #flag
> մnj (r\x1b9-\x19m?%\x10MZd4RE*ӟ>\x0b$O;;Ө@ҍ<h\x0e\x99#flag
> #state
> \x12W:TQK\x1a,9LR:#state
> #token
> \x1f\x0e\x1cbd\x0b\x03\xa4H\}z]\x0c#token
>
Ay now we got the flag :)
fun.c wont compile. It gives following error.
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x20): undefined reference to `main'
/usr/bin/ld: /tmp/ccBcq0J3.o: in function `initLibrary':
fun.c:(.text+0x11): undefined reference to `update_ooostate'
/usr/bin/ld: fun.c:(.text+0x22): undefined reference to `update_ooostate'
/usr/bin/ld: fun.c:(.text+0x33): undefined reference to `update_ooostate'
/usr/bin/ld: fun.c:(.text+0x44): undefined reference to `update_ooostate'
/usr/bin/ld: fun.c:(.text+0x55): undefined reference to `update_ooostate'
/usr/bin/ld: /tmp/ccBcq0J3.o:fun.c:(.text+0x66): more undefined references to `update_ooostate' follow
/usr/bin/ld: /tmp/ccBcq0J3.o: in function `initLibrary':
fun.c:(.text+0xe7): undefined reference to `getflag_builtin'
collect2: error: ld returned 1 exit status
Oops; that's my bad on the writeup. the actual command to compile is -shared not -static
Oh alright .
By the way I learned a lot in reversing static binaries from your write up. Thanks for that :-D
I am not bash guru and this one seems a complete magic.
May you please clarify:
1) So /bin/bash is not the standard bash, not even some less-standard replacement alternative,
but a program specifically crafted for these challenge, which has functions:
'update_ooostate' and 'getflag_builtin' defined in it, although, never called?
2) You did 'cat /bin/bash'. As I understand, normally,
you shouldn't have read/write permission on it, but for these challenge you had. Right?
3) I heard that on Linux you can run binaries with replaced libraries. Is it this line:
'enable -f /tmp/libn1.so pwned' ?
4) What is this token for:
TOKEN = b'cd /etc/ooobash && for file in *; do echo "#$file"; cat $file; echo "#$file";done' # If we exploit the suid we can run this too
@ahjain2706 I'm glad I could help :)
@nns2009 so the source of the modified bin/bash for this challenge is on the github (https://github.com/o-o-overflow/dc2020q-ooobash-public/tree/master/service/src/ooobash-src/bash-5.0). The functions update_ooostate() and getflag_builtin are builtin symbols that were added to the tree in the source. Clone that and you can see how update_ooostate() was used
2) Well technically yep I kinda did cat bin/bash (more of reversing). I had read permissions on the server; I HAD NO WRITE permissions.
3) Yep you can use LD_PRELOAD to run binaries with your preloads. It's useful when you want to capture events. that's one way to do this if you don't want to reverse. The line you quoted I used to turn on my own builtin
4) if I enable that token I can read the flag; state and token. Although not necessary for the exploit it was just a POC