주어진 zip 파일을 받아서 압축을 해제하면 문제 바이너리와 tar 파일이 나온다.

tar를 또 해제하면 아래와 같이 엄청나게 많은 라이브러리 파일이 들어있다.

정말 많은 양의 라이브러리가 있다.


우선 바이너리를 실행했다.

실행을 하면 처음에 입력을 한번 받고 두번 째 입력을 받는다.

얼추 유추해보면 처음 받는 수는 라이브러리이름 넘버를 받는 것으로 보인다.


두 번째 입력은 뭔가를 받는데 반응이 없다.


이번엔 다른 값을 넣어보았다.

이번엔 라이브러리를 임의로 55를 넣었다.

그리고 이번엔 '\\\\\\'를 넣었더니 명령어 에러 메시지가 나왔다.

두 번째 입력은 ls 뒤에 들어가도록 된 듯 하다.

이제 ida로 확인해보자.

2000의 main함수다.

input으로 라이브러리의 숫자를 받는것을 볼 수 있고,

해당 라이브러리의 test라는 함수의 주소를 가져와 실행시킨다.


나는 55를 넣었으니 lib_55.so 파일도 ida로 열었다.

lib_55.so에서는 lib_9068.so의 filter1 함수를 가져오고, lib_8658.so의 filter2함수를 가져온다.

그리고 system함수의 인자로 ls ""를 준다. 내가 입력한 값은 저 ls의 옵션 부분으로 들어간다.

lib_9068.so의 filter1함수다. 입력값의 필터로 보인다.

libc_8658.so의 filter2다.

f,l,g, bin, sh, bash가 필터로 막혀있다.

두 함수 다 두 번째 입력에 대한 필터 들이다.

이 부분을 우회 해야하는데 우회법을 찾지 못했고, 다른분의 라업을 보면 r2pipe라는 파이썬 라이브러리를 이용했다.


r2pipe는 radare2라는 리버싱 툴을 파이썬으로 사용 가능 하도록 한 API이다.

이 많은 라이브러리들 중 필터가 다른 라이브러리를 찾아서 문제를 풀었다.


import r2pipe
import ast

test = []
filter1 = []
filter2 = []

for i in range(1, 20000+1):
	r2 = r2pipe.open('./lib_{}.so'.format(i))
	if 'dlopen' in r2.cmd('ii'):
		test.append(i)
	if 'filter1' in r2.cmd('is'):
		filter1.append(i)
	if 'filter2' in r2.cmd('is'):
		filter2.append(i)
	if i % 12 == 0:
		print i
	r2.quit()

r = open('test', 'w')
r.write(str(test))
r.close()

r = open('filter1', 'w')
r.write(str(filter1))
r.close()

r = open('filter2', 'w')
r.write(str(filter2))

r2.cmd('ii')는 import 리스트를 출력하는 명령이고,

r2.cmd('is')는 symbol 리스트를 출력하는 명령이다.

해당 명령 설명은 radare2를 실행시켜 명령을 보면 나온다.

위 코드로 filter1, filter2를 가지고 있는 라이브러리 파일들의 리스트를 각각 추출해서 파일로 저장했다.(너무 오래 걸리기 때문에..)


이제 그 리스트로 lib_55.so의 filter1과 다른 필터를 가진 라이브러리를 찾을 것이다.

test = open('./test', 'r').read()
filter1 = open('./filter1', 'r').read()
filter2 = open('./filter2', 'r').read()

test = ast.literal_eval(test)
filter1 = ast.literal_eval(filter1)
filter2 = ast.literal_eval(filter2)

diff = []
for i in filter1:
    r2 = r2pipe.open('./lib_{}.so'.format(i))
    r2.cmd('aaa')
    filters = ['0x3b', '0x2a', '0x7c', '0x26', '0x24', '0x60', '0x3e', '0x3c', '0x72']
    out = r2.cmd('pdf @ sym.filter1')

    for filter in filters:
        if filter not in out:
            ff.append(i)
            break
    r2.quit()

print diff

각 라이브러리 filter1의 어셈블 코드를 받아 55의 필터와 비교하고 없다면 찾아내는 코드다.

lib_4323.so만 다르다고 나왔다.

filter1을 보니 | 문자가 필터에 없었다.

이번엔 이 lib_4323을 불러오는 test()함수를 가진 라이브러리를 찾아보자.

file = []
for i in test:
    r2 = r2pipe.open('./lib_{}.so'.format(i))
    if "./20000_so/lib_4323.so" in r2.cmd('iz'):
        print "find"
        file.append(i)

    if (i % 12 == 0):
        print i
    r2.quit()
print file

r2.cmd('iz')는 해당 바이너리의 string을 찾아내는 명령이다.

lib_17394.so가 나왔다.


lib_17394.so를 ida로 보면 lib_4323.so를 dlopen하고 system("입력값" 2 > /dev/null)을 실행한다. 아까 lib_55.so와는 많이 다른 코드를 가지고 있다.

여기서는 또 lib_11804.so를 dlopen한다. 다시 ida로 lib_11804.so을 열어보자.

아까 본 filter2와는 다른 필터를 가지고 있다. 여기는 bin, sh 다 필터에 없다.

따라서 lib_17394.so를 실행시키면 system("sh")을 실행시킬 수 있다!



'CTF > Codegate' 카테고리의 다른 글

codegate 2018 super marimo  (0) 2019.01.19
CodeGate2018 BaskinRobins31  (0) 2018.07.14
Codegate 2018 RedVelvet writeup  (0) 2018.02.04

+ Recent posts