[Reverse] 35C3 - juggle


juggle 97

Solves: 54

Can you help this restaurant Stack the right amount of Eggs in their ML algorithms?

Guest challenge by Tethys.

Note that you need to send a shutdown(2) after you sent your solution. The nmap netcat will do so for you, e.g.: ncat 35.246.237.11 1 < solution.xml

/usr/bin/ncat –help | grep -n 1 Ncat 7.60 ( https://nmap.org/ncat )

Files here: https://35c3ctf.ccc.ac/uploads/juggle-f6b6fa299ba94bbbbce2058a5ca698db.tar

XSL service is running in the server at a certain port, a dockerfile was provided which was cool, it helped me a lot in the debugging process, in the container environment I had no previous knowledge of xslt which took me more time in this challenge than it should.

Solution

  • The seed is not set in random so we can abuse it by doing very quick requests to get the same numbers
  • Identify which plate prints the flag
  • Use the plates in a certain order to achieve the condition necessary to print the flag

Walk-through

So I started by analysing the docker file, the container is using nsjail to isolate the /usr/bin/xalan service as we can see bellow:

Setting up the Docker container

1
2
3
4
5
FROM tsuro/nsjail
RUN apt-get install -y xalan
COPY challenge.min.xslt /home/user/
#COPY tmpflag /flag
CMD /bin/sh -c "/usr/bin/setup_cgroups.sh && su user -c '/usr/bin/nsjail -Ml --port 1337 --chroot / --user 1000 --group 1000 --cgroup_mem_max 209715200 --cgroup_pids_max 100 --cgroup_cpu_ms_per_sec 100 --rlimit_as max --rlimit_cpu max --rlimit_nofile max --rlimit_nproc max -- /usr/bin/stdbuf -i0 -o0 -e0 /usr/bin/maybe_pow.sh /usr/bin/xalan -xsl /home/user/challenge.min.xslt'"

Eventually I had to fix a line in the docker file at:

1
COPY challenge/challenge.min.xslt /home/user/

The challenge.min.xslt was located in the root directory after extracting the files, so I ended up changing this into:

1
COPY challenge.min.xslt /home/user/

So lets start to build the image with docker build:

1
$ sudo docker build -t juggle .

After this you can list the image created:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
permute latest 1603e833509a 23 hours ago 147MB
juggle latest b4c26a022c1e 33 hours ago 205MB
tsuro/nsjail latest 8774d7aad732 2 days ago 156MB
adalovelace/nodejs latest c2a6e42b25c8 2 days ago 63.7MB
node 6-alpine c45d42c157e3 2 days ago 55.6MB
nginx latest 02256cfb0e4b 2 days ago 109MB
alpine latest 3f53bb00af94 8 days ago 4.41MB
centos 7 1e1148e4cc2c 3 weeks ago 202MB
postgres latest f9b577fb1ed6 4 weeks ago 311MB
thecolonial/police-quest 1.0 0ea244849eb0 4 weeks ago 345MB
ubuntu 14.04 f17b6a61de28 5 weeks ago 188MB
mysql latest f991c20cb508 6 weeks ago 486MB
httpd latest 2a51bb06dc8b 6 weeks ago 132MB
debian latest 4879790bd60d 6 weeks ago 101MB
seccon_pwn latest 3749dfe7031c 7 weeks ago 2.06GB
skysider/pwndocker latest a24dde07a423 7 weeks ago 2.02GB
elasticsearch 2 5e9d896dc62c 3 months ago 479MB
postgres 9.6.2 b3b8a2229953 19 months ago 267MB
postgres 9.6.1 4023a747a01a 23 months ago 265MB

As we can see in the list the juggle image was created (the name we gave it).

With this we can start running the container by just using docker container run:

1
$ sudo docker run -it -p 1337:1337 --name 35c3_juggle juggle bash

After this a bash console will pop-up in the container unfortunately the command in the end of the docker didn’t work maybe something related with nsjail, I don’t know maybe I did something wrong when I was trying to connect to the service, I even tryed to rerun the command inside the container but it always gave me an error, so to not loose much time identifying it I setted up very quiclky a service with socat, socat isn’t installed in this container so I needed to install it via apt-get:

1
root@b0927d9b031a $ socat tcp-listen:1337,fork,reuseaddr EXEC:/usr/bin/xalan -xsl /home/user/challenge.min.xslt'

Since I forwarded the port 1337 from the host to the container port 1337 with the parameter -p in the docker run command. Now I could connect from the host directly to the localhost with ncat localhost 1337 without getting any errors from the server.

XML format analysis

So it’s time to start analysing the challenge.min.xslt file, this file was minimized so I searched for an online tool to beautify to make it more readable, so lets start with the beginning:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math"
xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xsl math exsl">
<xsl:template match="/meal">
<all>
<xsl:if test="count(//plate) > 300">
<xsl:message terminate="yes">You do not have enough money to buy that much food</xsl:message>
</xsl:if>
<xsl:variable name="chef-drinks">
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
</xsl:variable>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="exsl:node-set($chef-drinks)//value"/>
<xsl:with-param name="food-eaten" select="1"/>
<xsl:with-param name="course" select="course[position() = 1]/plate"/>
<xsl:with-param name="drinks" select="state/drinks"/>
</xsl:call-template>
</all>
</xsl:template>
<xsl:template name="consume-meal">
<xsl:param name="chef-drinks"/>
<xsl:param name="food-eaten"/>
<xsl:param name="course"/>
<xsl:param name="drinks"/>
...

So if you don’t know about xslt is a language that parses a xml document, and with that you can do things like converting that xml into html in a very easy way. Right at the beginning we can see what kind of structure of xml they want :

1
<xsl:template match="/meal">

The match parameter will look in the xml document from the root for a tag , from this you can look up into the elements inside of it. Now right after setting this an variable is declared with some random numbers (drinks), variables like in any other language are used to store values to be used later, in xslt is no different.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<xsl:variable name="chef-drinks">
<value>
<xsl:variable name="chef-drinks">
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
<value>
<xsl:value-of select="round(math:random() * 4294967296)"/>
</value>
</xsl:variable>

This random implementation looks already suspicious, looks it it doesn’t even have any kind of seed, and if it has a seed it probably is the current time. Now right after declaring this drinks with random numbers it does a template call as you can see bellow:

1
2
3
4
5
6
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="exsl:node-set($chef-drinks)//value"/>
<xsl:with-param name="food-eaten" select="1"/>
<xsl:with-param name="course" select="course[position() = 1]/plate"/>
<xsl:with-param name="drinks" select="state/drinks"/>
</xsl:call-template>

You can think of this like it’s a function call in a normal language, the name of the function is consume-meal and its arguments are right below, the declaration of consume-meal is just below this code, but before doing that lets analyse the selects for the arguments since they give us hints about how the xml document should be built.

So for the first parameter:

1
<xsl:with-param name="chef-drinks" select="exsl:node-set($chef-drinks)//value"/>

so exsl:node-set will just grab all the values from the variable $chef-drinks and pass it into the function as it was an array, explaining the //value part, the first / is referencing the the tag of the variable <xsl:variable name=”chef-drinks”> and the /value is referencing to the \<value> tag, this extracts the variable random number drinks and sets them as an array to be used in the template “function”.

So for the second parameter:

1
<xsl:with-param name="food-eaten" select="1"/>

The food-eaten parameter is initialized into 1 and this an integer variable that ill keep track of the number of plates you consume, after analysing consume-meal you will see that there’s a limit of plates you can eat that’s why they are tracking this number here.

So for the third parameter:

1
<xsl:with-param name="course" select="course[position() = 1]/plate"/>

Since we are inside a template tag match meal, by analysing this select it looks it inside the tag meal, our xml will need to have a course tag (\<course>) and plate tags inside of it, this works like a hierarchy from the left to right, the part [position() = 1] is just selecting the first plate inside the course tag, an example xml could be like this:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<meal>
<course>
<plate>
1st plate
</plate>
<plate>
2nd plate
</plate>
</course>
</meal>

So course[position() = 1] will select the first plate inside course so the parameter course will be set into :

1
2
3
<plate>
1st plate
</plate>

So for the fourth parameter:

1
<xsl:with-param name="drinks" select="state/drinks"/>

Once again this will select all the drinks declared inside state and drinks tags, so two new tags will needed to be added inside meal tag.

Based on the information we have now an example xml can be build like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<meal>
<course>
<plate>
1st plate
</plate>
<plate>
2nd plate
</plate>
</course>
<state>
<drinks>1</drinks>
<drinks>2</drinks>
</state>
</meal>

And now finally analysing the “function” consume-meal:

1
2
3
4
5
6
7
8
9
10
11
<xsl:template name="consume-meal">
<xsl:param name="chef-drinks"/>
<xsl:param name="food-eaten"/>
<xsl:param name="course"/>
<xsl:param name="drinks"/>
<xsl:if test="$food-eaten > 30000">
<xsl:message terminate="yes">You ate too much and died</xsl:message>
</xsl:if>
<xsl:if test="count($drinks) > 200">
<xsl:message terminate="yes">You cannot drink that much</xsl:message>
</xsl:if>

Right at the beginning the parameters of the “function” are being declared, and two ifs are checking if we ate more than 30k plates or more than 200 drinks, so if we eat of drink more than that , the function terminates and “prints” a message to the user.

After this we come up with a new if, it checks if the number of plates is higher than 0, and a new tag xsl:choose, which is like a switch-case from the c language the when tags are the case clauses, and it only enters it if the condition is true of course. Right before the choose two variables are being initialized, c and r , the variable c will get the head (first element) of the plate list inside the tag course, and r will be setted into the rest plates of the list, position()>1 will select all the plates above the position 1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<xsl:if test="count($course) > 0">
<xsl:variable name="c" select="$course[1]" />
<xsl:variable name="r" select="$course[position()>1]" />
<xsl:choose>
<xsl:when test="count($c/宫保鸡丁) = 1">
<xsl:message>
<chef-drinks>
<xsl:copy-of select="$chef-drinks"/>
</chef-drinks>
</xsl:message>
<xsl:message>
<drinks>
<xsl:copy-of select="$drinks"/>
</drinks>
</xsl:message>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="$chef-drinks"/>
<xsl:with-param name="food-eaten" select="$food-eaten + 1"/>
<xsl:with-param name="course" select="$r"/>
<xsl:with-param name="drinks" select="$drinks"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="count($c/paella) = 1">
<xsl:variable name="newdrinks">
<value>
<xsl:value-of select="$c/paella + 0"/>
</value>
<xsl:copy-of select="$drinks"/>
</xsl:variable>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="$chef-drinks"/>
<xsl:with-param name="food-eaten" select="$food-eaten + 1"/>
<xsl:with-param name="course" select="$r"/>
<xsl:with-param name="drinks" select="exsl:node-set($newdrinks)//value"/>
</xsl:call-template>
</xsl:when>
...

Clause Analysis

I will only explain 3 clauses, since my solution only uses 3 it makes sense to only explain these ones.

Analysing the first case-clause:

1
<xsl:when test="count($c/宫保鸡丁) = 1">

We can already update out XML into this, since $c is a plate we will need a new tag which are named into this weird names, if we want to enter into this clause:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<meal>
<course>
<plate>
<宫保鸡丁>4</宫保鸡丁>
</plate>
</course>

<state>
<drinks>
1
</drinks>

<drinks>
1
</drinks>
</state>
</meal>

Now analysing the code when we enter this clause 宫保鸡丁 , as we can see below it only prints the current chef drinks and the current drinks, in the end is recalling consume-meal, this will form a recursive function that will iterate all the plates created in the course tag, as we can see the parameters passed the only thing that changes is the $course the $r is passed into this parameter so we don’t get stuck in a infinite loop which is the usually the thing you do when creating a recursive function, oh the other change is obvious the incrementing of the variable food-eaten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<xsl:when test="count($c/宫保鸡丁) = 1">
<xsl:message>
<chef-drinks>
<xsl:copy-of select="$chef-drinks"/>
</chef-drinks>
</xsl:message>
<xsl:message>
<drinks>
<xsl:copy-of select="$drinks"/>
</drinks>
</xsl:message>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="$chef-drinks"/>
<xsl:with-param name="food-eaten" select="$food-eaten + 1"/>
<xsl:with-param name="course" select="$r"/>
<xsl:with-param name="drinks" select="$drinks"/>
</xsl:call-template>
</xsl:when>

Analysing the second case-clause:

1
2
3
4
5
6
7
8
9
10
11
<xsl:when test="count($c/दाल) = 1">
<xsl:if test="count($chef-drinks) = 0">
<xsl:copy-of select="document('/flag')"/>
</xsl:if>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="$chef-drinks"/>
<xsl:with-param name="food-eaten" select="$food-eaten + 1"/>
<xsl:with-param name="course" select="$r"/>
<xsl:with-param name="drinks" select="$drinks"/>
</xsl:call-template>
</xsl:when>

Now analysing the code when we enter this clause दाल, we can see it will print and select a document “/flag” which will contain the flag we need, perhaps we need satisfy the condition count($chef-drinks) = 0, the chef-drinks is initialized with 5 random numbers (chef-drinks) so we need to find a clause that removes items from $chef-drinks so we reach the count of 0.

Analysing the third case-clause:

1
2
3
4
5
6
7
8
9
10
11
12
13
<xsl:when test="count($c/Борщ) = 1">
<xsl:variable name="arg0">
<value>
<xsl:value-of select="$drinks[1] + 0"/>
</value>
</xsl:variable>
<xsl:call-template name="consume-meal">
<xsl:with-param name="chef-drinks" select="$chef-drinks[position() > 1 or $chef-drinks[1] != $arg0]"/>
<xsl:with-param name="food-eaten" select="$food-eaten + 1"/>
<xsl:with-param name="course" select="$r"/>
<xsl:with-param name="drinks" select="$drinks[position() > 1]"/>
</xsl:call-template>
</xsl:when>

Now analysing the code when we enter this clause Борщ, the first drink in $drinks (drinks declared inside the state tag) is setted into arg0 variable, now analysing the recalling parameters we can see chef-drinks is being modified:

1
<xsl:with-param name="chef-drinks" select="$chef-drinks[position() > 1 or $chef-drinks[1] != $arg0]"/>

The select will remove the head of $chef-drinks based on a condition position() > 1 or $chef-drinks[1] != $arg0, so to make this condition work we need either for both condition to be both false, or to at least position() > 1 to be true, unfortunately position() > 1 will never be true in this situation because position() will return the current position order in xml and since it’s not associated into any tag it will always return 1 because is associated to the root element meal, 1 > 1 is always false so we need to make $chef-drinks[1] != $arg0 to return false as well, the $chef-drinks are declared as random in the begining but as I said before the randomness is implemented in a wrong way, if we do fast requests we can get the same numbers as we can analyse it here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ncat 35.246.237.11 1 < solution.xml
Reading input document from stdin...
XSLT message: 2790719341256416733922614505473645015994193916258 (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 1, column 1.)
Source tree node: meal.
XSLT message: (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 1, column 1.)
Source tree node: meal.
<?xml version="1.0" encoding="UTF-8"?><all/>⏎

$ ncat 35.246.237.11 1 < solution.xml
Reading input document from stdin...
XSLT message: 2790719341256416733922614505473645015994193916258 (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 1, column 1.)
Source tree node: meal.
XSLT message: (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 1, column 1.)
Source tree node: meal.
<?xml version="1.0" encoding="UTF-8"?><all/>

The only case-clause that prints the $chef-drinks for us is 宫保鸡丁 , so the xml used to print the samples above was:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<meal>
<course>
<plate>
<宫保鸡丁>4</宫保鸡丁>
</plate>
</course>

<state>

</state>
</meal>

But we ran into a problem here right? as you can see it prints chef-drinks into a single number, 2790719341256416733922614505473645015994193916258, it looks like the message printing is joining all the 5 elements into a one number, for example if the random numbers were 1,2,3,4,5 the number that would be printed is 12345 , the problem is sometimes each drink will have a different length and we don’t have any way to tell which length each element has, so I decided to analyse a lot of occurrences.

To make sure the length of each $chef-drink I decided to modify a little bit the challenge.min.xslt file in my docker container so I could print those numbers as well, so right after the declared parameters in consume-meal I added this line:

1
<xsl:copy-of select="$chef-drinks" />

So at every iteration of consumer-meals the $chef-drinks will be printed like this:

1
2
3
4
5
6
7
$ ncat localhost 1337 < solution.xml
Reading input document from stdin...
XSLT message: 993763458325537011481963110810288894381216985659 (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 65, column 65.)
Source tree node: meal.
XSLT message: (Occurred in entity 'file:///home/user/challenge.min.xslt', at line 70, column 70.)
Source tree node: meal.
<?xml version="1.0" encoding="UTF-8"?><all><value>993763458</value><value>3255370114</value><value>819631108</value><value>1028889438</value><value>1216985659</value><value>993763458</value><value>3255370114</value><value>819631108</value><value>1028889438</value><value>1216985659</value></all>

So after this I did this bash script:

1
2
3
4
5
6
##35.246.237.11 1
for i in {1..1000}
do
var1=$(ncat localhost 1337 < solution.xml | grep -Poh '\d{4,}')
echo $var1;
done

Running it into a file:

1
$ bash rofl.sh > out

So after saving the outputs into a file I got something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
1326253109254338424518246198631339281333178972257 1326253109 2543384245 182461986 3133928133 3178972257 1326253109 2543384245 182461986 3133928133 3178972257
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
72103983017631206362496312023648539152890537599 721039830 17631206 3624963120 2364853915 2890537599 721039830 17631206 3624963120 2364853915 2890537599
....

So after this I wrote a python script that reads this outputs and counts the length every number:

1
2
3
4
with open('out','r') as f:
lines = f.readlines()
for l in lines:
print map(len,l.strip().split(' ')[:-5])

The output is something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
....
[47, 9, 10, 10, 9, 9]
[47, 9, 10, 10, 9, 9]
[47, 9, 10, 10, 9, 9]
[47, 9, 10, 10, 9, 9]
[47, 9, 10, 10, 9, 9]
[50, 10, 10, 10, 10, 10]
[50, 10, 10, 10, 10, 10]
[50, 10, 10, 10, 10, 10]
[46, 10, 9, 8, 9, 10]
[46, 10, 9, 8, 9, 10]
[46, 10, 9, 8, 9, 10]
[46, 10, 9, 8, 9, 10]
[50, 10, 10, 10, 10, 10]
[50, 10, 10, 10, 10, 10]
[50, 10, 10, 10, 10, 10]
[50, 10, 10, 10, 10, 10]
...

From the outputs I analysed that when the single number had a length of 50, the chef-drinks would always have an equal length of 10, the other lengths diverged into different things so I decided to only extract the numbers if the single number has a length of 50. So now we need to create a xml file according with the info we just got, but it needs to be done dynamically at least of the part of the drinks, because we need to be really fast on the requests to get the same number it’s only possible if you do in a program. So the structure the xml solution we want to form needs to be something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<meal>
<course>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>

<plate>
<दाल>4</दाल>
</plate>
</course>

<state>
<drinks>random_number_extracted</drinks>
<drinks>random_number_extracted</drinks>
<drinks>random_number_extracted</drinks>
<drinks>random_number_extracted</drinks>
<drinks>random_number_extracted</drinks>
</state>
</meal>

We need 5 plates of Борщ because we need to reduce the count of chef-drinks to zero, and each iteration of Борщ will reduce the $chef-drinks by one, the final plate दाल is to finally print the flag, so I wrote two scripts to do this the first one is a simplified version of my bash script:

1
2
var1=$(ncat 35.246.237.11 1 < solution.xml | grep -Poh '\d{4,}')
echo $var1;

Before the python script I prepared this xml file so I didn’t need to create every tag in python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<meal>
<course>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>
<plate>
<Борщ>1</Борщ>
</plate>

<plate>
<दाल>4</दाल>
</plate>
</course>

<state>

</state>
</meal>

And finally my python script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-

import subprocess
import os
import xml.etree.ElementTree as ET
tree = ET.parse('solution2.xml')
root = tree.getroot()

for x in xrange(100):
a = subprocess.check_output(['bash','rofl.sh']).strip().split(' ')
if (len(a[0]) == 50):
state = root.getchildren()[1]
for i in range(0,50,10):
b = ET.SubElement(state,'drinks')
b.text = a[0][i:i+10]
break
# create a new XML file with the results
mydata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+ET.tostring(root, encoding="utf-8") +'\n\n'
myfile = open("items2.xml", "w")
myfile.write(mydata)

And now running it all:

1
2
3
$  bash -c "python juggle.py && ncat 35.246.237.11 1 < items2.xml"
Reading input document from stdin...
<?xml version="1.0" encoding="UTF-8"?><all><flag>35C3_The_chef_gives_you_his_compliments</flag></all>

The flag was 35C3_The_chef_gives_you_his_compliments