首页
社区
课程
招聘
[原创][writeup]CTFHUB-ret2VDSO
发表于: 2023-3-11 15:16 20154

[原创][writeup]CTFHUB-ret2VDSO

2023-3-11 15:16
20154

Arch: amd64-64-little<br>
RELRO: Partial RELRO<br>
Stack: No canary found<br>
NX: NX enabled<br>
PIE: PIE enabled<br>

以下是main函数初始化完后的栈构造

除了Canary之外的保护都开了,由于开启了PIE无法直接获悉具体指令地址,所以无法直接构建ROP<br>

system调用位于main函数中低2字节为0x0AD2

位于RBP-0x18处是main函数地址<br>
位于RSP+0x10处是VDSO基址

或在GDB中 vmmap<br>
0xffffffffff600000 0xffffffffff601000 --xp 1000 0 [vsyscall]

cat /proc/1/maps | grep vsyscal<br>
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]

对于这个实现方法,成功在本地打通并且getShell,但是在远程却并不适用,题目名叫做Ret2VDSO,直接使用Vsyscall我也觉得应该不是出题人本意,但是我并没有完全理解VDSO和该程序的利用,也没有找到相关类似题目的WP,根据我对vsyscallvdso的理解推测或许是靶机上压根就没有vsyscall,所以对于栈溢出的利用仅到此为止;

我曾尝试爆破VDSO基址,并加上0x5FC作为偏移来作为RetGadGet,但是这个方法不论是在远程还是本地都没成功,原因是在x64下,该地址有3个字节也既12位是随机的,不同于x32下仅有1字节,爆破概率是1/256;在本程序中爆破概率低达1/16777216,在绞尽脑汁想不出如何通过栈溢出来打通该程序时,确实抱着侥幸尝试过爆破VDSO基址,但不论本地还是远程最终都没能打通,即使打通了本地,也许我找的VDSO文件的ret偏移0x5FC在远程上也并不适用,所以我最终放弃了

根据分析可知以下三点

由于程序中的seed根据time()来生成,所以这是可以被预估的,只需要提前预估未来的某一个符合rand结果小于9位数用户可输入的时间戳并且等时间到时发送内容即可

我对该机制的理解还是过于浅显,以至于无法用出题人希望的方式解出这道题,目 前这题作为遗留问题,在我理解深入后再回过头来思考这题的解法

find / -name '*vdso*.so*'

int getint()
{
//buf大小为16字节
  char buf[16]; // [rsp+0h] [rbp-10h]
//仅允许用户输入8个字节
  read(0, buf, 8uLL);
  return atoi(buf);//将输入转为数字并返回
}
 
int menu()
{
  puts("------welcome------");
  puts("1.get gift");
  puts("2.overflow");
  puts("3.exit");
  puts("[+]give me your choice:");
  return getint();
}
 
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int seed; // eax
  int inputNum; // ebx
  char buf[56]; // [rsp+0h] [rbp-50h] BYREF
  int choice; // [rsp+38h] [rbp-18h]
  int counter; // [rsp+3Ch] [rbp-14h]
 
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  counter = 2;
  do
  {
    if ( !counter )//如果counter为0则结束循环
      break;
    choice = menu();//获取用户输入
    if ( choice == 1 )
    {
      --counter;
      puts("input num:");
      seed = time(0LL);//将当前时间戳作为seed【不安全的引用】
      srand(seed);
      inputNum = getint();//获取用户输入【注意是先获取seed后才等待输入】
      if ( inputNum == rand() )//对比输入和rand结果,如果一致则直接getshell
        system("/bin/sh");
    }
    if ( choice == 2 )
    {
      --counter;
      puts("hello from ctfhub");
      read(0, buf, 0xD0uLL);//【栈溢出】
    }
  }
  while ( choice != 3 );//即使输入3也会再跑一次循环【逻辑错误】
  return 0;
}
int getint()
{
//buf大小为16字节
  char buf[16]; // [rsp+0h] [rbp-10h]
//仅允许用户输入8个字节
  read(0, buf, 8uLL);
  return atoi(buf);//将输入转为数字并返回
}
 
int menu()
{
  puts("------welcome------");
  puts("1.get gift");
  puts("2.overflow");
  puts("3.exit");
  puts("[+]give me your choice:");
  return getint();
}
 
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int seed; // eax
  int inputNum; // ebx
  char buf[56]; // [rsp+0h] [rbp-50h] BYREF
  int choice; // [rsp+38h] [rbp-18h]
  int counter; // [rsp+3Ch] [rbp-14h]
 
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  counter = 2;
  do
  {
    if ( !counter )//如果counter为0则结束循环
      break;
    choice = menu();//获取用户输入
    if ( choice == 1 )
    {
      --counter;
      puts("input num:");
      seed = time(0LL);//将当前时间戳作为seed【不安全的引用】
      srand(seed);
      inputNum = getint();//获取用户输入【注意是先获取seed后才等待输入】
      if ( inputNum == rand() )//对比输入和rand结果,如果一致则直接getshell
        system("/bin/sh");
    }
    if ( choice == 2 )
    {
      --counter;
      puts("hello from ctfhub");
      read(0, buf, 0xD0uLL);//【栈溢出】
    }
  }
  while ( choice != 3 );//即使输入3也会再跑一次循环【逻辑错误】
  return 0;
}
.text:0000000000000A38     ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000000A38     public main
.text:0000000000000A38     main proc near                          ; DATA XREF: _start+1D↑o
.text:0000000000000A38
.text:0000000000000A38     buf= byte ptr -50h
.text:0000000000000A38     choice= dword ptr -18h
.text:0000000000000A38     counter= dword ptr -14h
.text:0000000000000A38
.text:0000000000000A38     ; __unwind {
.text:0000000000000A38     push    rbp
.text:0000000000000A39     mov     rbp, rsp
.text:0000000000000A3C     push    rbx
.text:0000000000000A3D     sub     rsp, 48h
.text:0000000000000A41     ; 8:   setvbuf(_bss_start, 0LL, 2, 0LL);
.text:0000000000000A41     mov     rax, cs:__bss_start
.text:0000000000000A48     mov     ecx, 0                          ; n
.text:0000000000000A4D     mov     edx, 2                          ; modes
.text:0000000000000A52     mov     esi, 0                          ; buf
.text:0000000000000A57     mov     rdi, rax                        ; stream
.text:0000000000000A5A     call    _setvbuf
.text:0000000000000A5A
.text:0000000000000A5F     ; 9:   setvbuf(stdin, 0LL, 1, 0LL);
.text:0000000000000A5F     mov     rax, cs:stdin@@GLIBC_2_2_5
.text:0000000000000A66     mov     ecx, 0                          ; n
.text:0000000000000A6B     mov     edx, 1                          ; modes
.text:0000000000000A70     mov     esi, 0                          ; buf
.text:0000000000000A75     mov     rdi, rax                        ; stream
.text:0000000000000A78     call    _setvbuf
.text:0000000000000A78
.text:0000000000000A7D     ; 10:   v8 = 2;
.text:0000000000000A7D     mov     [rbp+counter], 2
.text:0000000000000A84     jmp     loc_B10
.text:0000000000000A84
.text:0000000000000A89     ; ---------------------------------------------------------------------------
.text:0000000000000A89     ; 15:     choice = getInput();
.text:0000000000000A89
.text:0000000000000A89     loc_A89:                                ; CODE XREF: main+DC↓j
.text:0000000000000A89     mov     eax, 0
.text:0000000000000A8E     call    printMenu                       ; 打印菜单并获取用户输入数字
.text:0000000000000A8E                                             ; 1:getGift,判断用户输入和随机数是否相同
.text:0000000000000A8E                                             ; 2:overflow,栈溢出
.text:0000000000000A8E                                             ; 3:结束
.text:0000000000000A8E
.text:0000000000000A93     mov     [rbp+choice], eax
.text:0000000000000A96     ; 16:     if ( choice == 1 )
.text:0000000000000A96     cmp     [rbp+choice], 1
.text:0000000000000A9A     jnz     short loc_ADE
.text:0000000000000A9A
.text:0000000000000A9C     ; 18:       --v8;
.text:0000000000000A9C     sub     [rbp+counter], 1               
; ↓↓↓↓↓↓↓↓↓↓用户输入为1,getGift↓↓↓↓↓↓↓↓↓↓
.text:0000000000000AA0     ; 19:       puts("input num:");
.text:0000000000000AA0     lea     rdi, aInputNum                  ; "input num:"
.text:0000000000000AA7     call    _puts
.text:0000000000000AA7
.text:0000000000000AAC     ; 20:       seed = time(0LL);
.text:0000000000000AAC     mov     edi, 0                          ; timer
.text:0000000000000AB1     call    _time
.text:0000000000000AB1
.text:0000000000000AB6     ; 21:       srand(seed);
.text:0000000000000AB6     mov     edi, eax                        ; seed
.text:0000000000000AB8     call    _srand
.text:0000000000000AB8
.text:0000000000000ABD     ; 22:       inputNum = getInputNumber();
.text:0000000000000ABD     mov     eax, 0
.text:0000000000000AC2     call    getInputNumber
.text:0000000000000AC2
.text:0000000000000AC7     mov     ebx, eax
.text:0000000000000AC9     ; 23:       if ( inputNum == rand() )
.text:0000000000000AC9     call    _rand
.text:0000000000000AC9
.text:0000000000000ACE     cmp     ebx, eax
.text:0000000000000AD0     jnz     short loc_ADE
.text:0000000000000AD0
.text:0000000000000AD2     ;system("/bin/sh");getShell代码位于mainAD2处
.text:0000000000000AD2     lea     rdi, command                    ; "/bin/sh"
.text:0000000000000AD9     call    _system                        
; ↑↑↑↑↑↑↑↑↑↑↑用户输入为1:getGift↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:0000000000000AD9
.text:0000000000000ADE     ; 26:     if ( choice == 2 )
.text:0000000000000ADE
.text:0000000000000ADE     loc_ADE:                                ; CODE XREF: main+62↑j
.text:0000000000000ADE                                             ; main+98↑j
.text:0000000000000ADE     cmp     [rbp+choice], 2
.text:0000000000000AE2     jnz     short loc_B0A                  
; ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓用户输入为2:overflow↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
.text:0000000000000AE2
.text:0000000000000AE4                               ; 28:       --v8;
.text:0000000000000AE4     sub     [rbp+counter], 1
.text:0000000000000AE8     ; 29:       puts("hello from ctfhub");
.text:0000000000000AE80    lea     rdi, aHelloFromCtfhu            ; "hello from ctfhub"
.text:0000000000000AEF     call    _puts
.text:0000000000000AEF
.text:0000000000000AF4     ; 30:       read(0, buf, 0xD0uLL);
.text:0000000000000AF4     lea     rax, [rbp+buf]
.text:0000000000000AF8     mov     edx, 0D0h                       ; nbytes
.text:0000000000000AFD     mov     rsi, rax                        ; buf
.text:0000000000000B00     mov     edi, 0                          ; fd
.text:0000000000000B05     call    _read                          
; ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑用户输入为2:overflow↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:0000000000000B05
.text:0000000000000B0A                               ; 33:   while ( choice != 3 );
.text:0000000000000B0A
.text:0000000000000B0A    loc_B0A:                                ; CODE XREF: main+AA↑j
.text:0000000000000B0A    cmp     [rbp+choice], 3
.text:0000000000000B0E    jz      short loc_B1C
.text:0000000000000B0E
.text:0000000000000B10    ; 13:     if ( !v8 )
.text:0000000000000B10
.text:0000000000000B10    loc_B10:                                ; CODE XREF: main+4C↑j
.text:0000000000000B10    cmp     [rbp+counter], 0
.text:0000000000000B14    ; 14:       break;
.text:0000000000000B14    jnz     loc_A89
.text:0000000000000B14
.text:0000000000000B1A    jmp     short loc_B1D
.text:0000000000000B1A
.text:0000000000000B1C    ; ---------------------------------------------------------------------------
.text:0000000000000B1C
.text:0000000000000B1C    loc_B1C:                                ; CODE XREF: main+D6↑j
.text:0000000000000B1C    nop
.text:0000000000000B1C
.text:0000000000000B1D    ; 34:   return 0;
.text:0000000000000B1D
.text:0000000000000B1D    loc_B1D:                                ; CODE XREF: main+E2↑j
.text:0000000000000B1D    mov     eax, 0
.text:0000000000000B22    add     rsp, 48h
.text:0000000000000B26    pop     rbx
.text:0000000000000B27    pop     rbp
.text:0000000000000B28    retn
.text:0000000000000B28    ; } // starts at A38
.text:0000000000000B28
.text:0000000000000B28                               main endp
.text:0000000000000A38     ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000000A38     public main
.text:0000000000000A38     main proc near                          ; DATA XREF: _start+1D↑o
.text:0000000000000A38
.text:0000000000000A38     buf= byte ptr -50h
.text:0000000000000A38     choice= dword ptr -18h
.text:0000000000000A38     counter= dword ptr -14h
.text:0000000000000A38
.text:0000000000000A38     ; __unwind {
.text:0000000000000A38     push    rbp
.text:0000000000000A39     mov     rbp, rsp
.text:0000000000000A3C     push    rbx
.text:0000000000000A3D     sub     rsp, 48h
.text:0000000000000A41     ; 8:   setvbuf(_bss_start, 0LL, 2, 0LL);
.text:0000000000000A41     mov     rax, cs:__bss_start
.text:0000000000000A48     mov     ecx, 0                          ; n
.text:0000000000000A4D     mov     edx, 2                          ; modes
.text:0000000000000A52     mov     esi, 0                          ; buf
.text:0000000000000A57     mov     rdi, rax                        ; stream
.text:0000000000000A5A     call    _setvbuf
.text:0000000000000A5A
.text:0000000000000A5F     ; 9:   setvbuf(stdin, 0LL, 1, 0LL);
.text:0000000000000A5F     mov     rax, cs:stdin@@GLIBC_2_2_5
.text:0000000000000A66     mov     ecx, 0                          ; n
.text:0000000000000A6B     mov     edx, 1                          ; modes
.text:0000000000000A70     mov     esi, 0                          ; buf
.text:0000000000000A75     mov     rdi, rax                        ; stream
.text:0000000000000A78     call    _setvbuf
.text:0000000000000A78
.text:0000000000000A7D     ; 10:   v8 = 2;
.text:0000000000000A7D     mov     [rbp+counter], 2
.text:0000000000000A84     jmp     loc_B10
.text:0000000000000A84
.text:0000000000000A89     ; ---------------------------------------------------------------------------
.text:0000000000000A89     ; 15:     choice = getInput();
.text:0000000000000A89
.text:0000000000000A89     loc_A89:                                ; CODE XREF: main+DC↓j
.text:0000000000000A89     mov     eax, 0
.text:0000000000000A8E     call    printMenu                       ; 打印菜单并获取用户输入数字
.text:0000000000000A8E                                             ; 1:getGift,判断用户输入和随机数是否相同
.text:0000000000000A8E                                             ; 2:overflow,栈溢出
.text:0000000000000A8E                                             ; 3:结束
.text:0000000000000A8E
.text:0000000000000A93     mov     [rbp+choice], eax
.text:0000000000000A96     ; 16:     if ( choice == 1 )
.text:0000000000000A96     cmp     [rbp+choice], 1
.text:0000000000000A9A     jnz     short loc_ADE
.text:0000000000000A9A
.text:0000000000000A9C     ; 18:       --v8;
.text:0000000000000A9C     sub     [rbp+counter], 1               
; ↓↓↓↓↓↓↓↓↓↓用户输入为1,getGift↓↓↓↓↓↓↓↓↓↓
.text:0000000000000AA0     ; 19:       puts("input num:");
.text:0000000000000AA0     lea     rdi, aInputNum                  ; "input num:"
.text:0000000000000AA7     call    _puts
.text:0000000000000AA7
.text:0000000000000AAC     ; 20:       seed = time(0LL);
.text:0000000000000AAC     mov     edi, 0                          ; timer
.text:0000000000000AB1     call    _time
.text:0000000000000AB1
.text:0000000000000AB6     ; 21:       srand(seed);
.text:0000000000000AB6     mov     edi, eax                        ; seed
.text:0000000000000AB8     call    _srand
.text:0000000000000AB8
.text:0000000000000ABD     ; 22:       inputNum = getInputNumber();
.text:0000000000000ABD     mov     eax, 0
.text:0000000000000AC2     call    getInputNumber
.text:0000000000000AC2
.text:0000000000000AC7     mov     ebx, eax
.text:0000000000000AC9     ; 23:       if ( inputNum == rand() )
.text:0000000000000AC9     call    _rand
.text:0000000000000AC9
.text:0000000000000ACE     cmp     ebx, eax
.text:0000000000000AD0     jnz     short loc_ADE
.text:0000000000000AD0
.text:0000000000000AD2     ;system("/bin/sh");getShell代码位于mainAD2处
.text:0000000000000AD2     lea     rdi, command                    ; "/bin/sh"
.text:0000000000000AD9     call    _system                        
; ↑↑↑↑↑↑↑↑↑↑↑用户输入为1:getGift↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:0000000000000AD9
.text:0000000000000ADE     ; 26:     if ( choice == 2 )
.text:0000000000000ADE
.text:0000000000000ADE     loc_ADE:                                ; CODE XREF: main+62↑j
.text:0000000000000ADE                                             ; main+98↑j
.text:0000000000000ADE     cmp     [rbp+choice], 2
.text:0000000000000AE2     jnz     short loc_B0A                  
; ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓用户输入为2:overflow↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
.text:0000000000000AE2
.text:0000000000000AE4                               ; 28:       --v8;
.text:0000000000000AE4     sub     [rbp+counter], 1
.text:0000000000000AE8     ; 29:       puts("hello from ctfhub");
.text:0000000000000AE80    lea     rdi, aHelloFromCtfhu            ; "hello from ctfhub"
.text:0000000000000AEF     call    _puts
.text:0000000000000AEF
.text:0000000000000AF4     ; 30:       read(0, buf, 0xD0uLL);
.text:0000000000000AF4     lea     rax, [rbp+buf]
.text:0000000000000AF8     mov     edx, 0D0h                       ; nbytes
.text:0000000000000AFD     mov     rsi, rax                        ; buf
.text:0000000000000B00     mov     edi, 0                          ; fd
.text:0000000000000B05     call    _read                          
; ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑用户输入为2:overflow↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
.text:0000000000000B05
.text:0000000000000B0A                               ; 33:   while ( choice != 3 );

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-3-13 09:48 被LeaMov编辑 ,原因: 上传样本,修改md格式
上传的附件:
收藏
免费 8
支持
分享
最新回复 (3)
雪    币: 26245
活跃值: (63287)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2
建议附件上传到论坛一份
2023-3-12 10:02
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
3
建议上传一下(如果还在) 不然样本很容易丢失 
2023-3-12 23:46
0
雪    币: 1868
活跃值: (3303)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4
r0Cat 建议上传一下(如果还在) 不然样本很容易丢失
好的
2023-3-13 09:46
0
游客
登录 | 注册 方可回帖
返回
//