题目

给了三个文件ecrypt1.bin,readme.txt,rnd

其中readme.txt:

$ ./rnd crypt1.png ecrypt1.bin

Solve

看到前面有一个$,猜测可能和linux系统有关,这一条信息有点像使用./目录下的rnd对crypt1.png进行某种操作,输出为ecrypt1.bin.

file一下

file /home/mangofeng/桌面/rnd
/home/mangofeng/桌面/rnd: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=6a1443272dd530117d3c63884e195120a845c499, stripped

是一个32位ELF文件,通过32ida反编译找主函数可以得到伪代码:

int __cdecl main(int a1, char **a2)
{unsigned int v3; // eaxFILE *v4; // [esp+10h] [ebp-10h]FILE *v5; // [esp+14h] [ebp-Ch]char ptr; // [esp+1Fh] [ebp-1h] BYREFif ( a1 <= 2 )return 1;v3 = time(0);srand(v3);v4 = fopen(a2[1], "rb");v5 = fopen(a2[2], "wb");while ( fread(&ptr, 1u, 1u, v4) == 1 ){ptr ^= rand() % 256;fwrite(&ptr, 1u, 1u, v5);}fclose(v4);fclose(v5);return 0;
}
  unsigned int v3; // eaxFILE *v4; // [esp+10h] [ebp-10h]FILE *v5; // [esp+14h] [ebp-Ch]char ptr; // [esp+1Fh] [ebp-1h] BYREF/*上面这些都是定义了各种变量*/
  if ( a1 <= 2 )return 1;//判断了一个a1是否小于等于2,若是的话,则返回1,下面语句都不会执行,则我们的a1应大于2
v3 = time(0);
//time()参数一般为0或者Null相当于 取系统时间()
如:
#include <iostream>
#include <ctime>
using namespace std;int main()
{int a;a=time(0);//time(0)返回的是系统的时间(从1970.1.1午夜算起),单位:秒cout<<a<<endl;
}
//1648089941
即时间戳:
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
在CPP中,时间戳默认就是10位,其精度是秒
  srand(v3);

先提一提rand()

rand()函数常用来生成伪随机数
rand()函数是使用线性同余法做的,它并不是真的随机数,因为其周期特别长,所以在一定范围内可以看成随机的。
rand()函数不需要参数,它将会返回0到RAND_MAX之间的任意的整数。

如:

#include<time.h>
#include<stdlib.h>
#include<iostream>
using namespace std;int main()
{for(int i = 0; i < 10; i++)
{cout << rand()<<endl;
}
}/*
41
18467
6334
26500
19169
15724
11478
29358
26962
24464*/

srand()

srand()为初始化随机数发生器,用于设置rand()产生随机数时的种子。传入的参数seed为unsigned int类型,通常我们会使用time(0)或time(NULL)的返回值作为seed。
srand(time(0));
for(int i = 0; i < 10; i++)
{cout << rand() << endl;
}
/*22954
16198
7083
19454
25323
32035
19825
3031
24100
11374*/

而且:

此方法默认参数为srand(1),当种子确定以后,输出也是确定的.例:

srand(1);
for(int i = 0; i < 10; i++)
{cout << rand() << endl;
}
cout<<time(0);
/*
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
1648090722
*/
/*
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
1648090746
*/

我运行了两次上述代码,可通过时间戳看出,发现rand()结果是一样的.


让我们再回到反编译的代码:

  v3 = time(0);srand(v3);

通过上述分析我们得知,此处设置了一个种子,种子为运行时的时间戳.

  v4 = fopen(a2[1], "rb");v5 = fopen(a2[2], "wb");
//这句话就有点像python里面的,v4就是我要读取数据的文件,打开方式为read binary;v5就是我要写入数据的文件,打开方式为write binary;
  while ( fread(&ptr, 1u, 1u, v4) == 1 ){ptr ^= rand() % 256;fwrite(&ptr, 1u, 1u, v5);}
fread函数用于从文件流中读取数据,其函数原型为:
size_t fread(void* buffer, size_t size, size_t count, FILE*stream);【参数设置】
1)
buffer为接收数据的地址,对于fread来书是要读出数据的地址,即数据保存的地址
2)  size是要读出内容的单字节数。
3)  count是要进行读出size字节的数据项的个数。
4)  stream为目标文件指针
fwrite()
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);-- buffer:指向数据块的指针-- size:每个数据的大小,单位为Byte(例如:sizeof(int)就是4)-- count:数据个数-- stream:文件指针

然后大概就是原来文件的数据与生成的rand()异或得到新的文件数据.

然后我们之前分析了srand()函数,只要其传入参数一致,生成的rand()即一致

然后我们去分析一下生成文件ecrypt1bin的相关更改时间

可以通过stat命令查看文件的状态

stat /home/mangofeng/桌面/ecrypt1.bin文件:/home/mangofeng/桌面/ecrypt1.bin大小:45989           块:96         IO 块:4096   普通文件
设备:801h/2049d        Inode:21607       硬链接:1
权限:(0766/-rwxrw-rw-)  Uid:( 1000/mangofeng)   Gid:( 1000/mangofeng)
最近访问:2022-03-24 11:12:41.937672000 +0800
最近更改:2014-11-22 22:46:30.000000000 +0800    #this
最近改动:2022-03-24 11:12:42.026137518 +0800
创建时间:2022-03-24 11:12:41.938137515 +0800

将该更改时间转换为时间戳

a = "2014-11-22 22:46:30"
#将其转换为时间数组
import time
timeArray = time.strptime(a, "%Y-%m-%d %H:%M:%S" )
#转换为时间戳:
timeStamp = int (time.mktime(timeArray))
print(timeStamp)
#1416667590

或者

stat --printf=%Y /home/mangofeng/桌面/ecrypt1.bin
1416667590

然后用一下解密脚本:

#include <stdio.h>
#include <stdlib.h>int main(int argc, char *argv[]) {FILE *cipher = fopen(argv[1], "rb");FILE *plain = fopen(argv[2], "wb");unsigned int seed = atoi(argv[3]);int c;srand(seed);c = (fgetc(cipher) & 0xff) ^ (rand() & 0xff);while (!feof(cipher)) {fputc(c, plain);c = (fgetc(cipher) & 0xff) ^ (rand() & 0xff);}fclose(plain);fclose(cipher);
}

然后用一下gcc编译

gcc /home/mangofeng/桌面/decode.c -o /home/mangofeng/decode┌──(mangofeng㉿kali)-[~]
└─$ gcc /home/mangofeng/桌面/decode.c -o /home/mangofeng/桌面/decode                                                                                               ┌──(mangofeng㉿kali)-[~]
└─$ /home/mangofeng/桌面/decode /home/mangofeng/桌面/ecrypt1.bin /home/mangofeng/桌面/output.png 1416667590

其中N都不是太大的值,可以分解成pq

先一步一步干吧,用yafu分解一下

N1=0xB8AE199365
print(int(N1))
p1 = 913799
q1 = 868019
N2=0xB86E78C811
print(int(N2))
p2 = 904727
q2 = 875543
N3=0x7BD4071E55
print(int(N3))
p3 = 890459
q3 = 597263
assert (q1*p1==N1)
assert (q2*p2==N2)
assert (q3*p3==N3)

因为N都不是太大,就会导致加密的m不能太大,再看有三块,推测flag应该是三块短的字符串拼凑在一起

解法一:

已知flag格式为:SECCON{}

则试一试一块flag大概有多长

N, B, FLAG = 0xB8AE199365, 0xFFEEE, b'SECCON{'
for i in range(1, len(FLAG)+1):M = bytes_to_long(FLAG[0:i])print(FLAG[0:i],'\t',str(hex(M * (M + B) % N)),end="\n")
b'S'     0x52fc213
b'SE'    0x54f0cb0bf
b'SEC'   0x8c0ad9b877
b'SECC'          0x704d68c1fb
b'SECCO'         0x8d5051562b
b'SECCON'        0x2339eed575
b'SECCON{'       0x1bce931b16

发现到五位长度以后,明文就经过了取模操作,即我们猜测flag每一块被分成不超过五位的明文块

验证一下

B=[0xFFEEE,0xFFFEE,0xFEFEF]
C=[0x8D5051562B,0x5FFA0AC1A2,0x6008DDF867]
p=[913799,904727,890459]
q=[868019,875543,597263]
N=[p1*q1,p2*q2,p3*q3]
test=b'SECCO'
M=bytes_to_long(test)
print(bool(hex(M*(M+B[0])%N[0])=='0x8d5051562b'))
#True

则我们就可以去用ascii爆破剩下的两个明文块,每个长度最多为5;

N, B =N[1],B[1]
for i in range(32, 127):for j in range(32, 127):for k in range(32, 127):M = ('N{' + chr(i) + chr(j) +chr(k))M =bytes_to_long(bytes(M, encoding='UTF-8'))if ((M * (M + B) % N) == int(0x5FFA0AC1A2)):print('N{' + chr(i) + chr(j) + chr(k))
#N{Ra_
for i in tqdm.tqdm(range(32, 127)):for j in range(32, 127):for k in range(32, 127):for l in range(32,127):MM = chr(i) + chr(j) +chr(k)+chr(l)+'}'MM =bytes_to_long(bytes(MM, encoding='UTF-8'))if (((MM * (MM + B[2]))% N[2]) == int(0x6008DDF867)):print(chr(i) + chr(j) + chr(k)+chr(l)+'}')break
#b1_N}

SECCON{Ra_b1_N}

解法二:

N大概在2^40左右,要想从modN下找到一个值满足条件是不现实的

但我们已经把N分解成了p,q,根据中国剩余定理可以把条件拆成两个
{ C p ≡ m p ⋅ ( m p + B ) ( m o d p ) C q ≡ m q ⋅ ( m q + B ) ( m o d q ) \begin{cases}C_p\equiv m_p\cdot(m_p+B)\pmod{p}\\C_q\equiv m_q\cdot(m_q+B)\pmod{q}\end{cases} {Cp​≡mp​⋅(mp​+B)(modp)Cq​≡mq​⋅(mq​+B)(modq)​
p,q都比较小,可以爆破,寻找到满足上述两式的 m p 和 m q m_p和m_q mp​和mq​
{ m ≡ m p ( m o d p ) m ≡ m q ( m o d q ) \begin{cases}m\equiv m_p\pmod{p}\\m\equiv m_q\pmod{q}\end{cases} {m≡mp​(modp)m≡mq​(modq)​
然后就可以根据CRT求解出m啦。

def CRT(moudle,a):M = reduce((lambda x,y : x * y),moudle)result = 0for mi in moudle:Mi = M // miinv_Mi = gmpy2.invert(Mi,mi)result = (result + a[moudle.index(mi)] * Mi * inv_Mi) % Mreturn (result % M)
for i in range(0,3):for a1 in [m_p for m_p in range(p[i]) if (C[i] % p[i]) == (m_p * (m_p + B[i])) % p[i]]:# 遍历所有小于p[i]的值for a2 in [m_q for m_q in range(q[i]) if (C[i] % q[i]) == (m_q * (m_q + B[i])) % q[i]]:# 遍历所有小于q[i]的值x = CRT([p[i],q[i]],[a1,a2])print(long_to_bytes(x))
b'eh\xc6Q('
b'W_V"\xa7'
b'aN\xb3q\xd0'
b'SECCO'
b'\x86V\t\xc5\xee'
b'i\xf3\x16f\xc4'
b'N{Ra_'
b'2\x18_\x025'
b'\x19\xa2\x97\xdf\xe9'
b'%\xf5"\x992'
b'U\xde\xd4\x954'
b'b1_N}'
SECCON{Ra_b1_N}

总结

解出png的过程还挺有意思的,就是后面这个加密方式有点头疼,爆破就完了。

参考

M3ng@L哥哥的链接

https://blog.csdn.net/u013745804/article/details/82379266

https://blog.csdn.net/stf1065716904/article/details/73656036

https://blog.csdn.net/yang2011079080010/article/details/52528261

https://blog.csdn.net/km_moon/article/details/84737151

https://blog.csdn.net/weixin_44604541/article/details/113613885

SECCON-CTF-2014-Decrypt-It-easy相关推荐

  1. [SECCON CTF 2022] 只两个小题pwn_koncha,rev_babycmp,crypto_pqpq

    从一开始入门CTF,SECCON的名字就如雷贯耳,如今参加了又很失望,距离参加这种比赛还是太远了.只是作了两个100人以上作出来的小题. pwn koncha int __cdecl main(int ...

  2. [SECCON CTF 2016 Quals] Chat 分析与思考

    CTFSHOW吃瓜杯,PWN方向第三题竟是SECCON原题,于是当时没有仔细研究,直接套用了其他大佬的EXP(第二第三第四题都是各大比赛的原题,网上可以直接找到写好的EXP......) 既然现在比赛 ...

  3. [青少年CTF]Misc—Easy by 周末

    更新日期:2022年12月6日 青少年CTF训练平台MIsc-Easy部分的WP 有错误请在评论区指出,万分感谢!!! 个人博客:https://www.st1ck4r.top/ (- ̄▽ ̄)- 0x ...

  4. linux 堆溢出 pwn 指南,新手科普 | CTF PWN堆溢出总结

    学习汇总 序言 自从加入RTIS交流群, 在7o8v师傅,gd大佬的帮助下,PWN学习之路进入加速度.下面是八周学习的总结,基本上是按照how2heap路线走的.由于八周内容全写,篇幅太长,这里只讲述 ...

  5. 2月国内外CTF比赛时间汇总来了!

    ● 从事网络安全行业工作,怎么能不参加一次CTF比赛了! 小编作为一个CTF比赛老鸟,以每次都能做出签到题为荣! 下面给大家分享一下2月份CTF比赛时间,比赛按时间先后排序,国内国外的都有哦! 文章末 ...

  6. CTF 音频隐写 大总结

    赛题概览 Nuit du Hack CTF Qualifications: Here, kitty kitty! 环境 Windows 考察点 WAV音频文件隐写术 Python基础 密码学 工具 A ...

  7. 第七届XCTF国际网络攻防联赛总决赛战队巡礼!

    Super Guesser国际联合战队创建于2020年,成立伊始便在HITCON.SECCON.Dragon CTF等大型国际CTF赛事中大放异彩,接连斩获赛事冠军.2021年,Super Guess ...

  8. “饶派杯”XCTF车联网安全挑战赛战队巡礼!

    2023年5月31日,"饶派杯" XCTF车联网安全挑战赛将于江西省上饶市重磅开赛.本届大赛由江西省委网信办.江西省工信厅.上饶市人民政府主办,旨在深入贯彻落实国家网络强国和交通强 ...

  9. 任务四:Crypto学习

    任务四:Crypto学习 内容: 学习掌握长度扩展攻击,明白攻击原理,知道攻击的条件,实践长度扩展攻击,题目:Plaid CTF 2014 Crypto 250 Parlor,完成WP. 长度扩展攻击 ...

  10. Seccon-ctf-2016-pwn-cheer_msg 题解

    Write Up 文件信息 漏洞定位 利用分析 wp 总结 文件信息 样本来自2016年Seccon ctf的一道pwn题–cheer_msg,同时这道题目也给了libc文件,减少了漏洞利用难度. 检 ...

最新文章

  1. 时间卷积网络(TCN)在 NLP 多领域发光,RNN 或将没落
  2. “AlphaGo之父”获最新一届ACM计算奖
  3. PCA原理分析和Matlab实现方法(三)
  4. Linux下ctrl+c,ctrl+z,ctrl+d的区别
  5. 3D bin picking(散乱零件抓取)
  6. mysql 字段类型设计_Mysql字段类型设计相关问题!-阿里云开发者社区
  7. 怎么样把百度搜索引入自己的网站JS实现(附源代码)
  8. 景安mysql主机_景安虚拟主机使用教程
  9. 《信息处理技术员考试考前冲刺预测卷及考点解析》下午案例复习重点
  10. 计算机思维导论在线测试题库,计算机导论题库有答案.docx
  11. 大数据基础概念思维导图
  12. C语言与或非应用案例,与或非(生活中与或非例子)
  13. 分享一个能对java代码进行“tokenize”的python库
  14. 用Python+selenium实现在全国报刊索引上搜集资料
  15. 点云前视图与俯视图生成
  16. instruction-tuning
  17. 导出带有合计行的excel
  18. C++中函数重载是如何实现
  19. 【畅通工程 HDU - 1232 】【并查集模板题】
  20. 计算机二级Python基础知识点整理

热门文章

  1. 7-4 大炮打蚊子 (20分)__C++
  2. 关于定量控制污水流量计的安装、维护与定期比对及计量
  3. 数据结构实验课:实验五、二叉树操作及应用
  4. Java基础之父类引用指向子类对象
  5. mysql 日期group_MySql 使用GROUP BY 按照日期分组统计
  6. hive sql中传date 指定后的“%Y-%m-%d“格式,需要加引号
  7. 数值计算一阶常微分方程求解实现
  8. 最新Navicat Premium 16 激活中文版 适用于win和mac版
  9. windows全局消息钩子的一个BUG
  10. k8s各组件的端口说明