[ Pwntools ] Python

DPOS·2021년 7월 13일
4
post-thumbnail

지금까지 간단간단한 문제들은 필요가 없었지만, 앞으로 나올 문제들을 푸는데 쉽고 간편해지기 때문에 pwntools를 사용합니다. 루비는 개인적으로 몇번 만져보니 취향에 맞아서 추가로 정리하는 것이고 주는 파이썬입니다.

기본적인 개념 서술

pwntools의 개념과 사용하는 이유

  먼저 pwntools에 대해 간단히 설명하겠습니다. 이 친구는 어떤 소프트웨어, 어플리케이션 이런것이 아니라 파이썬이나 루비에서 사용하는 라이브러리입니다. 용도는 이름에서 보시다싶이 포너블에 사용되는 도구가 되겠죠.

설치와 사용법

1) 파이썬 라이브러리 설치하는 법

sudo apt update
sudo apt install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
sudo python3 -m pip install --upgrade pip
sudo python3 -m pip install --upgrade pwntools

설치는 위 명령어대로 진행해주시면 됩니다.

2) 파이썬에서의 사용법


먼저, pwntools를 사용하기 위해 pwn모듈을 임포트해줍니다.

from pwn import *

접속

### ssh는 ssh("username", "ip", port=, password="")
shp = ssh("DPOS", "localhost", port=22, password="abcd1234")

### nc는 remote(ip, port)
ncp = remote("localhost", 8888)

### localfile의 경우는 process(path)
lfp = process("/home/dpos/문서/sample")

데이터 입출력

### 데이터 받기
p.recv(byte)
# 원하는 byte만큼 데이터를 가져오는데 공란일 경우엔 데이터 전체를 가져옴
p.recvline()
# 데이터 한줄을 가져올 때 사용
p.recvuntil('A')
# 데이터를 A라는 문자를 찾을 때까지 받아오고, \n을 할 경우 recvline()과 같은 결과

### 데이터 전송
p.send(data)
# 데이터를 전송하는데 보통 read()에 사용
p.sendline(data)
# 데이터를 라인단위로 보내는데 보통 scanf(), puts(), gets()에 사용 + 마지막에 /n 추가

### 유저 & 쉘 입출력
p.interactive()
# 사용자가 쉘과 직접 데이터를 주고 받음

패킹과 언패킹

### packing
# 32bit 패킹
var = p32(0x12345678)                    # var = \x78\x56\x34\x12 or xV4\x12
var = p32(0xABCD)                        # var = \x68\x67\x66\x65 or \xcd\xab\x00\x00
# 64bit 패킹
var = p64(0x12345678)                    # var = \x00\x00\x00\x00\x78\x56\x34\x12 or xV4\x12\x00\x00\x00\x00
# big endian으로 패킹
var = p32(0x12345678, endian ='big') # var = \x124Vx
var = p64(0x12345678, endian ='big') # var = \x00\x00\x00\x00\x124Vx

### unpacking
# 32bit 언패킹
var = u32("\x78\x56\x34\x12")            # var = 305419896 -(hex)-> (0x12345678)
var = u32("xV4\x12")
var = u32("\x68\x67\x66\x65")            # var = 1701209960 -(hex)-> (0x65666768)
var = u32("\xcd\xab\x00\x00")
# 64bit 언패킹
var = u64("xV4\x12\x00\x00\x00\x00") 	 # var = 305419896
var = u64("\x00\x00\x00\x00\x78\x56\x34\x12")

직접해보면 상상했던 \x78\x56\x34\x12 형태가 아니라 xV4\x12 이렇게 나오는 것을 볼 수 있는데 실제 사용에는 별 다른 문제가 없어서 그냥 사용하시면 됩니다. 정확한 값은 b'xV4\x12'로 나올텐데 아스키코드로 \x78 = x, \x56 = V, \x34 = 4 이렇게 각각 변환되어 나오는거라 실제 사용시에는 문제 없이 굴러갑니다.

실사용

그럼 이제 사용하는 방법도 알아봤으니 실제로 사용해보도록합시다.

1) 문제 코드 확인

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

int main()
{
    int a, b, c;
    int i = 1000;
    srand(time(0));

    while(i)
    {
        a = rand() % 5000;
        b = rand() % 5000;
        printf ("%d + %d = \n", a, b);
        printf (">>> ");
        scanf("%d", &c);
        if( a + b == c ) { printf("PASS\n"); }
        else { return 0; }
        i--;
    }

    printf("\nDH{FLAG}\n\n");

    return 0;
}

2) 스크립트 작성

위와 같은 코드가 있을때 다음과 같은 스크립트를 짤 수 있습니다.

from pwn import *

r = process("./DPOS") 			# DPOS실행 파일에 접근

for i in range(1000):
    ra = r.recvuntil("+")[:-2]		# "a +"를 슬라이싱해서 a만 얻음
    a = int(rawa)
    
    rb = r.recvuntil("=")[1:-2]		# " b ="을 마찬가지로 순수한 값만 얻음
    b = int(rawb)
      
    res = a + b

    r.sendline(str(res))		# scanf이기 때문에 한줄 입력값을 보냄

    r.recvuntil("PASS\n")		# "PASS\n"를 읽어옴
    
r.interactive()				# 유저에게 입출력 제어권을 넘김

이렇게 스크립트를 짜고 실행을 해보면
  나름 플래그인 값이 나오게 됩니다. 일단 이 예제가 제 마음에 들진 않지만 당장 생각나는 문제도 없고, 제 컴퓨터 상대로 bof를 하고 싶진 않아서 생각 가능한 선에서 더 적합하다 생각되는 예제가 있으면 바꿀 예정입니다.

profile
본인 전공빼고 다 하는 사람

1개의 댓글

comment-user-thumbnail
2021년 7월 14일

あまりにも簡単な ww

답글 달기