주어진 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 |