일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 금리인하
- 폰폰테스트
- 유튜버 김재석
- 이상형 만들기
- 리리남매
- 학교 개학 연기 4월
- 픽크루
- 조희연
- 제넥신
- 홍혜걸
- 김영권 아내
- 스페인 코로나
- libtins
- 은혜의 강 교회
- 킹덤 고근희
- 임영규
- 불가피
- 스콜피온킹
- 이태원 클라쓰 15회 예고
- 성남 코로나 확진자
- 최강욱
- 김재석
- 뭉쳐야 찬다
- 해킹
- 고민정
- 미국 금리인하
- 이지혜
- 김영권
- 성남은혜의강교회
- 양적완화
- Today
- Total
Dork's port
FTZ Level20 Write-up(FTZ Level20 풀이) 본문
우와~~~
마! 지! 막! 문제입니다 ㅎㅎ
역시 마지막 문제 답게 시간이 엄청 걸렸네요 ㅠㅠ
문제부터 보시죠!
문제가 심상치가 않습니다!
문제를 보니 버퍼는 80으로 선언되어있고 이번엔 fgets함수에서 길이 체크를 하는군요!
이 문제는 BOF가 아닌 FSB 즉! 포맷 스트링 버그를 이용해야 합니다.
혹시나 포맷 스트링을 모른다면 검색후에 다시 재 도전해보시길 바랍니다.
※포맷 스트링의 원리 및 해설은 자세하게 하지 않도록 하겠습니다.
이미 여러 문서에서 포맷스트링에 대한 이야기를 다루고 있으므로 저는 포맷스트링시에 몰랐던 부분에 대해 설명을 하도록하겠습니다.
정말로 시작해보죠!
우선 자연스럽게 이제 gdb를 열어 스택의 구조가 어떻게 되는지 보기 위해 열려고 했으나 main의 symbol이 존재하지 않는다고 합니다. 허허..
점점 불친절해져
그래서 ltrace를 이용하며 main의 시작 주소를 얻으려고 했으나 프롬포트가 떨어진체 아무런 반응도 없습니다.
재부팅이 필요합니다.. 시도하지마세요.
다만, 삽질의 과정에서 attackme의 파일을 copy하여 ltrace를 하면 정상적으로 open이 가능합니다.
그러나 이때 return Address를 구하려고 했으나 ASLR보안 기법이 적용되어 있어 계속 Return address의 주소를 구하지 못했습니다.
이거만 거의 하루 걸렸어요 ㅠㅠ
자 그러면 printf에 출력할 당시에 스택의 구조가 어떻게 되는지 보기 위해 출력을 해보도록 하겠습니다.
버퍼의 시작을 표시하기 위해 AAAA 및 스택을 보기 위해 %08x로 8자리씩 출력하도록 입력을 하였습니다.
포맷스트링의 기본적인 원리는 printf에서 포맷스트링을 만난 경우 Stack에서 pop을 한다는 것이 취약점으로 작용합니다.
그랬더니 AAAA출력을 제외하고 0000004f 4212ecc0 4207a759 41414141 로 printf 함수의 스택에서 buf까지의 거리는 총 12바이트 차이가 나는 것을 알 수 있습니다.
그렇다면 4번째 포맷스트링을 만날때 (pop을 4번하면) 버퍼의 시작 주소를 참조하는 값이 리턴되겠군요.
여기서 $를 이용하면 현재 스택으로 부터 n번째 스택을 참조할 수 있습니다(실제로 esp는 이동되지 않습니다. 즉, $로 참조 후 %x등과 같이 pop을 시도하면 스택의 처음부터 pop이 이루어 집니다).
%n$(format_string)
ex) $ %4$p
스택에서 부터 4번째 값을 p(주소)형식으로 출력
이때 return address를 이용할 수 없으므로 다른 개념을 이용해야합니다.
기본적으로 gcc에서는 생성자와 소멸자를 함께 컴파일 하는데 생성자는 main함수의 시작전에 실행되는 함수이고 소멸자는 main함수가 끝난 후 실행되는 함수 입니다.
ctors, dtors이라고 하며 아래와 같이 확인할 수 있습니다.
$ readelf -S ./attackme
There are 34 section headers, starting at offset 0x1dcc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 080480f4 0000f4 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048108 000108 000020 00 A 0 0 4
[ 3] .hash HASH 08048128 000128 000034 04 A 4 0 4
[ 4] .dynsym DYNSYM 0804815c 00015c 000080 10 A 5 1 4
[ 5] .dynstr STRTAB 080481dc 0001dc 000061 00 A 0 0 1
[ 6] .gnu.version VERSYM 0804823e 00023e 000010 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08048250 000250 000020 00 A 5 1 4
[ 8] .rel.dyn REL 08048270 000270 000010 08 A 4 0 4
[ 9] .rel.plt REL 08048280 000280 000020 08 A 4 b 4
[10] .init PROGBITS 080482a0 0002a0 000017 00 AX 0 0 4
[11] .plt PROGBITS 080482b8 0002b8 000050 04 AX 0 0 4
[12] .text PROGBITS 08048308 000308 000188 00 AX 0 0 4
[13] .fini PROGBITS 08048490 000490 00001b 00 AX 0 0 4
[14] .rodata PROGBITS 080484ac 0004ac 000008 00 A 0 0 4
[15] .eh_frame PROGBITS 080484b4 0004b4 000004 00 A 0 0 4
[16] .data PROGBITS 080494b8 0004b8 00000c 00 WA 0 0 4
[17] .dynamic DYNAMIC 080494c4 0004c4 0000c8 08 WA 5 0 4
[18] .ctors PROGBITS 0804958c 00058c 000008 00 WA 0 0 4
[19] .dtors PROGBITS 08049594 000594 000008 00 WA 0 0 4
[20] .jcr PROGBITS 0804959c 00059c 000004 00 WA 0 0 4
[21] .got PROGBITS 080495a0 0005a0 000020 04 WA 0 0 4
[22] .bss NOBITS 080495c0 0005c0 000008 00 WA 0 0 4
[23] .comment PROGBITS 00000000 0005c0 000132 00 0 0 1
[24] .debug_aranges PROGBITS 00000000 0006f8 000078 00 0 0 8
[25] .debug_pubnames PROGBITS 00000000 000770 000025 00 0 0 1
[26] .debug_info PROGBITS 00000000 000795 000a84 00 0 0 1
[27] .debug_abbrev PROGBITS 00000000 001219 000138 00 0 0 1
[28] .debug_line PROGBITS 00000000 001351 00027c 00 0 0 1
[29] .debug_frame PROGBITS 00000000 0015d0 000014 00 0 0 4
[30] .debug_str PROGBITS 00000000 0015e4 0006ba 01 MS 0 0 1
[31] .shstrtab STRTAB 00000000 001c9e 00012b 00 0 0 1
[32] .symtab SYMTAB 00000000 00231c 0006f0 10 33 54 4
[33] .strtab STRTAB 00000000 002a0c 00042b 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
이때 .ctors 및 .dtors의 구조는 가르키는 포인터로 가면 아래와 같은 형식을 지닙니다.
시작을 알리는 0xffffffff값과 마지막을 알리는 0x00000000 사이에 실제로 생성자나 소멸자가 알맞게 들어가게 됩니다.
0xffffffff <function address> <function address>...0x00000000
그래서 우리는 main이 종료되는 시점에서 자동으로 호출되는 함수인 소멸자를 쉘코드가 있는 Address로 바꿔줄 것 이며, 이때 확인한 주소 + 4의 주소를 바꿔 줘야합니다(주소의 시작에는 0xfffffffff의 값이 있으므로).
그럼 쉘코드를 한번 작동시켜보도록 하죠!
그러면 아래와 같이 명령을 작성하실 수 있습니다.
아래 명령에 대한 부분은 포맷스트링에 대한 이해가 필요하므로 별도로 다루거나 다른 문서를 참조하시는 것을 추천드립니다.
(글이 너무 길어져요 ㅠㅠ, 제가 이해한 걸 이해시킬 자신이 없어요... ㅠ)
그러면 아래와 같이 쉘이 떨어지면서 짜라라라란 Clear!!!!!!
길고 길었던 FTZ가 끝이 났네요!
조금만 더일찍했으면 좋았을 걸 ㅠㅠ 여정을 함께하시느라 수고하셨습니다.
다음엔 LOB로 찾아뵙겠습니다!
참조 : http://bbolmin.tistory.com/34
http://blog.naver.com/PostView.nhn?blogId=haks2198&logNo=220840244540&categoryNo=0&parentCategoryNo=0&viewDate=¤tPage=1&postListTopCurrentPage=1&from=postView
http://www.hackerschool.org/HS_Boards/data/Lib_system/amadohack_fs.txt
'Hackerschool FTZ Write-up' 카테고리의 다른 글
FTZ Level19 Write-up(FTZ Level19 풀이) (0) | 2018.03.26 |
---|---|
FTZ Level18 Write-up(FTZ Level18 풀이) (1) | 2018.03.26 |
FTZ Level17 Write-up(FTZ Level17 풀이) (0) | 2018.03.26 |
FTZ Level16 Write-up(FTZ Level16 풀이) (0) | 2018.03.26 |
FTZ Level15 Write-up(FTZ Level15 풀이) (0) | 2018.03.26 |