JuniorCTF 2013 예선풀이보고서 김성우 ( cd80 )
목차 1. 대회개요 2. 0번문제 3. 1번문제 4. 2번문제 5. 3번문제 6. 4번문제 7. 5번문제 8. 6번문제 9. 7번문제
1. 대회소개 이대회는 2013년 7월 26일오전 10시 ~ 오후 10시, 총 12시간동안진행된대회로 ETRI에서주최하고 GrayHash에서운영한청소년해킹방어대회이다. 대회는레벨업방식으로진행되었으며 1번암호학, 2번 pe리버싱, 3번웹, 4번 ~10 번 elf 리버싱으로문제가있었다슈퍼해커한명이대회를 2시간안에클리어해놀라웠던대회이다올클리어는총 7명이했으며본선진출자는 30위까지이다시상내역은다음과같다금상 (1위) 상금 200만원, 미래창조과학부장관상은상 (2위) 상금 100만원, ETRI( 한국전자통신연구원 ) 원장상은상 (3위) 상금 100만원, KISIA( 지식정보보안산업협회 ) 회장상동상 (4위) 상금 50만원, ETRI( 위와동일 ) 소프트웨어연구부문소장상 본선은 8 월 12 일역삼동한국과학기술회관에서치뤄지고 그전날인 8 월 11 일은리브렛세미나 1 회가개최되는역사적인날이다 (2014 년에도개최하니많이들와주세요 ) 평소공부하던내용인리버싱문제가많이나와재밌었다 다음엔포너블문제도조금내주시면좋을것같습니다 ( 쉽게..)
2. 0 번문제 0 번문제는해킹공부에있어필수라고할수있는한국어를이해할수있는지를 묻는문제이다 평소한국어공부를게을리했다면이문제에서멘붕했을것이다지금우린해커테스트를진행하려하고있고어느정도의실력을갖추고있다면크게어렵지않을것이란힌트를받았다대회규칙을읽고입력폼에확인을입력하란명령을받는다입력해보고엔터를눌러본다
축하받았다이제 level1 로넘어간다
3. 1 번문제 1 번문제다지금보니저옆에분무섭다 고대암호방식은시저암호밖에모른다 ㅋ
ㅋㅋ ㅋㅋㅋ
ㅋㅋㅋㅋㄳ 답은 ENDLESSROBOTWAR 이다 Key 를알아서게싱해주다니..
4. 2 번문제 리버싱문제다 시리얼같은거체크하나보다 해커친구 IDA 여기서하나팁. DialogBoxParamA 를분석할땐네번째인자에들어가는함수를분
석하면된다아닐때도있겠지만언젠진모르겠다 DialogBoxParamA 를통해받은문자열을받아올땐 GetDigItemTextA 를쓴다 DialogFunc 을더블클릭하고왼쪽밑에보면 이렇게 GetDigItemTextA 로문자열을받아오고처리하는루틴이있다함수밑에밑에 xor edx, 99h 하고 cmp edx, 0f1h 한담에 jnz loc_40120f 로분기하는형식의구조가아래에도계속반복되는걸보면이분기문의조건들을모두 zf=1이되게, 즉둘이같게만들어주면통과하는거같다
쭉보면 0x99랑 xor해서 0xf1이랑비교 0x99랑 xor해서 0xfc랑비교 0x99랑 xor해서 0xf5랑비교 0x99랑 xor해서 ecx랑비교하는데이바로위에박스보면 ecx에문자열을가져와 xor하는걸볼수있다. 따라서이건위에거랑같다. 즉 0xf5랑비교 0x99랑 xor해서 0xf6이랑비교 0x99랑 xor해서 0xb9랑비교 0x99랑 xor해서 0xf3이랑비교 0x99랑 xor해서 0xec랑비교 0x99랑 xor해서 0xf7이랑비교 0x99랑 xor해서 0xf0이랑비교 0x99랑 xor해서 0xf6이랑비교 0x99랑 xor해서 0xeb랑비교 0x99랑 xor해서 0xb9랑비교 0x99랑 xor해서 0xf1이랑비교 0x99랑 xor해서 0xf8이랑비교 0x99랑 xor해서 0xfa랑비교 0x99랑 xor해서 0xf2랑비교 0x99랑 xor해서 0xfc랑비교 0x99랑 xor해서 0xeb랑비교 0x99랑 xor해서 0xea랑비교너무힘들다이걸왜다썼지
이제 ~~ 랑을 0x99 랑차례대로 xor 해주면원래데이터가나온다 답은 hello junior hackers 다
5. 3 번문제 오웹이다 오로그인이다
오소스다????????????????? 오비번이다 오되나 오비번 iamapolicyhacker
6. 4 번문제 이번문제부턴다리눅스문제다그렇다고 pwn 하는문제들은아니고그냥리버싱 해서키파일읽는문제들이다 setuid 가걸린 chal 바이너리가있고 flag 가있다
복붙하고나서야창을투명하게해놨단걸깨달았다다음스샷부턴불투명하게해야겠다 Uid를입력하래서입력했더니 setreuid해주는것도아니고그냥종료한다부탁들어준다해놓고듣기만하는거랑뭐가다르지.. 나쁘다 위는 start 함수의일부인데아래에서 libc_start_main 함수를호출한다.
libc_start_main 함수의프로토타입은 int libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)); 이다. 복잡하지만여기서볼건첫번째인자다첫번째인자가 main함수의주소이다즉 libc_start_main함수를호출하기직전 push한 0x8048728이 main함수주소다 얘가메인함수다 putchar함수에 0xa가들어가니그냥 \n을출력한단걸알수있고그아래로세개의 puts는 ----------------------------------- Let me know what UID you want to be (Except root UID - 0) 이세줄이다
다음 printf는 UID: 이걸출력하고이제 esp+0x1c에유저입력을 scanf로받는다그후 printf에서 Ok.. you input [ 입력한 uid] UID 를출력하고이후에 scanf함수를기준으로다른함수를또호출하는데인자가 esp+0x1c다우리가입력한값으로어떤처리를하는것같다 이게그함수다여기서또간략한팁함수프롤로그이후의 ebp는 sfp를가르키고있고 ebp+4는 return address ebp + 8 부터첫번째인자를가르킨다그래서 0x80486fa는넘겨받은인자가 0인지를체크하고있다
Input 이 0 일때 puts 후 exit 을하는걸보아이부분이 0x8048700 ~ 0x8048717 에해당한다 다시코드를가져왔다그래서 0하고같지않다면인자 ( 우리가입력한값, uid) 를 eax에넣는데다음라인에서 movzwl %ax, %eax를한다 movzwl이뭔지몰라서검색해봤는데검색해도모르겠어서디버거로실행시켜봤다
아무변화가없다근데 movzwl의오퍼랜드를보니 %ax하고 %eax인걸보아 %eax의하위 2바이트가어떻게되는거같다 3바이트이상의데이터를넣어주면변화를확인할수있을것같아 305419896( 0x12345678 ) 을넣어줘봤다 그냥단순히 %ax 를 %eax 에넣어주는거였다
다시가져와봤다그럼 0x80485fc엔우리가입력한값의하위 2바이트만인자로들어가게된다즉 int형에서 short int형으로 type이변형된것이다 0x80485fc함수는길어서전체캡쳐는하지않았다코드가좀복잡해보이는데핵심부분만보면 ebp-0x3c 지역변수에인자를넣는다 ebp-0x3c 와 0 을비교해같지않으면 0x80486dc 로점프한다 그런데 0x80486dc는에필로그부분이다. 따라서 ebp-0x3c는 0이되어이쪽으로점프를하지않게해야한다이함수를호출하기전엔 4바이트전체를검사했고이번엔 2바이트만검사하니하위 2바이트가 0000이되도록아무수나넣어주면된다
-847249408 ( 0xcd800000 ) 을넣어보겠다 사실 0x10000 같은간단한값을넣어줘도되지만 cd80 이들어가면있어보일것같 다 답은 GoGoGoHackers!
7. 5 번문제
먼저 fopen(0x8048832, 0x8048830) 을하는데이는각각 0x8048830 = r 0x8048832 =./secret_key 즉 fopen(./secret_key, r ) 을합니다그래서 esp+0x2838에./secret_key 파일의내용을 fgets로읽어옵니다 (0x8048640 ~ 0x8048689) 그후 esp+0x2738 에 0x804a038의내용을 0x13바이트만큼읽어오는데
0x804a038 은 bss 영역입니다 근데코드에서 0x804a038에어떤값을할당해주는부분이없으니 0일것입니다근데이부분이이해가잘안돼서동적으로분석해봤는데이주소의이름이 stdin으로돼있었습니다사실아직이해는잘안되지만결론적으로저코드는 stdin에서 0x13바이트를 esp+0x2738로 fgets할것입니다 그후 strcmp(esp+0x2838, esp+0x2738) 을해 system 함수를실행하는데그에들 어가는인자는다시.rodata 덤프를보면 system함수의인자로 0x8048853이들어가므로 echo you got me 가될것입니다즉 system( echo you got me ); 한후 exit(0); 합니다이부분은입력값이키값과맞는지만확인해주기때문에그렇게쓸모있는부분은아닙니다
이부분은 0x8048751에있는 jmp 0x80486f0에의해무한루프를도는부분입니다 gets(esp+0x28) 를실행하고 esp + 0x18에 -1을집어넣고 %edi에 esp+0x28을넣고 ecx에 -1, %eax에 0 각각이렇게레지스터를세팅하고 repnz scas %es:(%edi), %al 명령을실행하니결과적으로 stdin으로들어온입력값의길이를구하는과정입니다그후 %ecx를 %eax에넣으니 %eax엔입력값길이 (null바이트포함 ) 이들어갑니다그후 eax-1을 ecx에넣어줍니다즉 ecx엔널바이트전까지의거리가들어갑니다 eax엔 esp+0x2738, edx엔 esp+0x28( 위에서 gets로받은곳 ) 를넣어준후 memcpy(esp+0x2738, esp+0x28, strlen(esp+0x28)); 을수행합니다이는첫번째 stdin(esp+0x2738에들어가는 stdin) 다음으로무한루프를돌며받는 stdin(esp+0x28에들어가는 stdin) 을 esp+0x2738에널바이트없이문자열만을복사합니다그런데이때 esp+0x28에 256바이트를넣어주게되면 esp+0x28에선문제가없지
만 memcpy로 esp+0x2738에 256바이트가들어가면서 esp+0x2738과 esp+0x2838 문자열이연결이됩니다그런데밑에서 printf(esp+0x2738) 을실행하므로 esp+0x2738과 esp+0x2838이연결이된다면 esp+0x2838의내용까지도출력됩니다따라서이문제는데이터복사가끊기지않는문자를 256바이트넣어주게되면 printf(esp+0x2738) 때 key값 (esp+0x2838) 까지출력되는것입니다 답은 DidYouLikeIt?
8. 6 번문제 마찬가지로바이너리분석문제입니다 Writeup 초반엔조금가볍게썼었는데쓰다보니피곤해서딱딱하게쓰게되네요 이번엔 list 란디렉토리도같이있습니다
Grayhash 와관련된문자열들이보입니다 먼저 argc 가 2 가아니면 puts(0x8048804); exit(0); 합니다 argc 는 2 로맞춰줘야하고 2 가맞다면 0x804859d(argv[1]) 을합니다 snprintf( ebp-0x4c, 0x80487e0, argv[1] ); 를합니다 0x80487e0 은 list/%s.txt 입니다
즉다시말해 snprintf( ebp-0x4c, list/%s.txt, argv[1] ); 을하는코드입니다 0x8048564 ( ebp-0x4c ) 받은인자 ( 위에서의 ebp-0x4c) 를 arg라하겠습니다먼저 0x8048760( arg, ebp-0x60 ) 을하는데이부분은코드가하는일에비해약간복잡하게되어있어풀이보고서에쓰진않겠지만 list/%d.txt가존재하는지를확인하는루틴입니다
이제이부분은 list/%d.txt 를 rb 옵션으로 fopen 하고 ebp-0x14c 에 fgets 해옵니다 그후 printf(ebp-0x14c) 로읽어온내용을출력합니다 우린 secret 파일을읽어야하므로심볼릭링크를걸어풀겠습니다 답은 real cool secret
9. 7 번문제 이부분은시간문제로 objdump 가아닌 ida 의 hex-ray 기능을이용하여풀이하였 습니다. 개인적으로풀이보고서를공개할때이부분의풀이를수정하고 8 번문제 풀이를추가할예정입니다 Key 를암호화처리하고출력해주는부분입니다
답은 GRAYHATWHITEHAT