S!_Jmini 2020. 1. 7. 10:28

pwntool 예시

 

2020-06-21 추가 설명 for 20

더보기

C언어만 배운 상태에서 .py 확장자인 python 언어를 사용하는 것이 익숙하지 않을 수 있다.

 

하지만 python과 c언어의 문법이 비슷하게 사용된다.

 

하지만 일부 표현이 다른 부분이 존재한다.

 

그래서 C언어와 다른 점을 간단하게 설명해주고자 한다.

 

 

1. C언어와 달리 자료형 선언이 필요가 없다.

 

c - ex)

int a = 3; char c = 'a';
int arr[5] = {1,2,3,4,5};

py- ex)

a = 3, c = 'a'
arr = [1,2,3,4,5]

 

즉, 자료형을 알아서 설정한다. 따라서 c언의 배열자료형도 python의 리스트 자료형으로 대체가능하다.

 

 

 

2. 조건문과 반복문에서 ( ) 와 같은 기호가 필요없다.

 

c - ex) 

 if(a>b && a>0){ return 0;}

py - ex) 

if a>b and a>0 : 
	return 0

* 또한 python은 c언어처럼 { } 안에 실행코드를 작성하는 것이 아니라 들여쓰기를 통해서 구분한다.

* c언어의 논리연산자가 python에서 일부 다르다. && -> and, || -> or 등등...

 

 

 

3. 함수의 선형 방식이 다르다.

 

c - ex)

int func(int a,int b){
	return a+b;
}

py - ex)

def func(a,b):
	return a+b

* python은 반환 형식이 정해져있지 않기 때문에 return이 존재하지 않는 경우도 있다.

 

 

 

4. 자료형 변경 방식이 다르다

 

c - ex)

a = (int)1.3

py - ex)

a = int(1.3)

 

이 외의 기능은 검색을 통해 충분히 찾을 수 있다.

 

추가사항

 

p = process('파일이름')

: p라는 변수에 '파일이름'을 인자로 하는 process함수를 담음

 

p.interactive()

: process함수에서 interactive 함수를 실행

 

 

 

 

0. pwntool 모듈 로드

from pwn import *

 

 

1. 파일 실행

[ local ]

p = process('파일이름')

ex) p = process('./test')

 

p = process(executable = '파일이름',argv='인자',env='환경변수')

ex) p = process(excutable = './test',argv=_argv,env=_env)

 

* argv 는 리스트 형식이여야하고 env 는 딕셔너리 형식이여야 한다

 

예시처럼 작성해도되구 이렇게 작성해도 된다!

 

 

[ server ]

p = remote('IP주소',포트)

ex) p = remote('127.0.0.1',5000)

 

s = ssh('사용자이름','IP주소',port='포트',password='PASSWORD')

 

p = s.run('파일이름')

ex) s = ssh('guest','127.0.0.1',port=5000,password='guest')

 

 

 

p.interactive()

* exploit 코드 마지막에 넣어주어야 shell을 획득한 상태를 유지할 수 있다

 

2. 데이터 전달하기

p.send('str1')

* scanf, read 에 값을 전달할 때 \n 포함없이 전달

ex) p.send('a'*4)

 

p.sendline('str1')

* gets 에 값을 전달할 때 \n 포함해서 전달

ex) p.sendline('a'*4)

 

 

p.sendafter('str1','str2')

* str1의 문자열을 만나고 나서 str2 전달 (\n 포함없이 전달)

ex) p.sendafter('end\n','a'*4)

 

p.sendlineafter('str1','str2')

* str1의 문자열을 만나고 나서 str2 전달 (\n 포함해서 전달)

ex) p.sendlineafter('end\n','a'*4)

 

 

 

3. 데이터 받기

 

p.recv('크기')

ex) tmp = p.recv(4) 

-> 출력된 문자 4개를 tmp 값에 저장

 

 

p.recvuntil('str1')

ex) tmp = p.recvuntil('end\n')

-> end\n 까지 모든 문자들을 tmp에 받아냄

 

 

 

4. 데이터 변환

* 패킹이란 리틀엔디안 표기법에 맞추어 값을 전달하기 위해 하는 작업을 말한다

[ 패킹 ]

p32('주솟값') & p64('주솟값')

* 32bit 에서는 p32, 64bit 에서는 p64 를 사용하며 각각 4byte, 8byte의 크기를 맞춰주어야 한다

ex) p.send(p32(0xDEADBEEF))

 

 

[ 언패킹 ]

u32('패킹된 값') & u64('패킹된 값')

ex) tmp = u64(p.recv(6).ljust(8,"\x00"))

* u64를 사용할땐 주로 ljust를 사용하는데 64bit 에서 libc 값은 6byte 이기 때문이다

   ljust를 사용하여 8byte로 만든 뒤 언패킹하자 !

 

ex) addr = 0xbffffd0

     tmp = u32(addr)

 

 

 

 


5. 유용한 페이로드 만들기

[ shell ]

 

(32bit 일반 shellcode)

asm(shellcraft.i386.sh()) 

 

(64bit 일반 shellcode)

context(arch = 'amd64', os = 'linux')

asm(shellcraft.amd64.sh())

 

 

​asm(shellcraft.'실행함수')

ex) pay = asm(shellcraft.system('/bin/sh'))

 

예시

 

 

[ FSB ]

 

fmtstr_payload(offset,{'덮어쓸 주소':'덮어쓸 값'})

ex) pay = fmtstr_payload(4,{'0x804a10':'0xbffffd10'})

 

 

 


ALSR 제어

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space