强网杯

一道整数相关的题~

opm

分析

保护全开,GOT可劫持:

1
2
3
4
5
6
7
8
➜  Desktop checksec opm
[*] '/root/Desktop/opm'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
➜ Desktop

分析有一个结构体表示role:

1
2
3
4
5
6
7
8
9
10
11
00000000 role            struc ; (sizeof=0x28, mappedto_6)
00000000 fpOutSlogan dq ? ; offset
00000008 nameP dq ? ; offset
00000010 nameLen dq ?
00000018 punchs dd ?
0000001C db ? ; undefined
0000001D db ? ; undefined
0000001E db ? ; undefined
0000001F db ? ; undefined
00000020 field_20 dq ?
00000028 role ends

有两个功能,添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
struct role *add()
{
struct role *tmpRole; // rbx
struct role *tmpRole3; // rbx
size_t nameLen; // rax
struct role *tmpRole4; // rbx
char buf[128]; // [rsp+0h] [rbp-1A0h]
struct role *tmpRole2; // [rsp+80h] [rbp-120h]
char *name; // [rsp+100h] [rbp-A0h]
struct role *v8; // [rsp+188h] [rbp-18h]

v8 = (struct role *)__readfsqword(0x28u);
tmpRole = (struct role *)operator new(0x20uLL);
initRole(tmpRole);
tmpRole2 = tmpRole;
tmpRole->fpOutSlogan = outSlogan;
puts("Your name:");
gets(buf);
tmpRole3 = tmpRole2;
tmpRole3->nameLen = strlen(buf);
nameLen = strlen(buf);
name = (char *)malloc(nameLen);
strcpy(name, buf);
tmpRole2->nameP = name;
puts("N punch?");
gets(buf);
tmpRole4 = tmpRole2;
tmpRole4->punchs = atoi(buf);
outSlogan(tmpRole2);
return tmpRole2;
}

此处有两个明显的栈溢出,但是由于有canary和pie不能直接覆写返回地址,buf之上有两个指针,能控制tmpRole2它指向role,于是可以对其进行一些控制,在添加结束程序会输出两个域,其中punchs是用户输入没什么用,但是nameP域是可控的,可以用来泄露数据:

1
2
3
4
int __fastcall outSlogan(struct role *a1)
{
return printf("<%s> said he can kill the boss with %lx punches\n", a1->nameP, a1->punchs);
}

而show函数是直接使用role结构体里的函数指针:

1
2
for ( i = totalRoles - 1; i >= 0; --i )
((void (__fastcall *)(struct role *, char *))roleList[i]->fpOutSlogan)(roleList[i], &buf);

利用

综上,我们的思路就是先泄露出堆地址与opm程序的地址,有这两个东西,就能控制堆进一步通过读取GOT泄露出libc地址,再试试onegadget什么的,妙呀~

  1. 对堆进行排布,使下次分配时,nameP之前的位置低字节为’\x00’,这样就可以使用部分覆盖改写
    //add一个role,在输入punchs处将tmpRole2指向前移25Bytes处,改写nameP使其指向它自身,此时就会输出堆地址
  2. add一个role,在输入punchs处将tmpRole2指向前移25Bytes处,改写nameP使其指向它自身前移8Bytes处,此时就会输出slogan地址
  3. add一个role,在输入punchs处将tmpRole2指向gets@got.plt-8处,改写无用位置,此时就会输出libc的地址
  4. add一个role,在输入punchs处将tmpRole2指向atoi@got.plt-24处,改写atoi为system
  5. add一个role,在输入punchs处输入’/bin/sh\0’getshell

结果