HGAME week2 (crypto/re复现)
文章目录
REVERSE
ezcpp
通过分析可以知道是tea加密,而且是常规的Tea加密,直接解密即可
根据反编译的代码可以知道Tea加密了a[0]和a[4] (不知道为啥,我看代码应该是a[0]和a[1],不理解)
a[1]和a[5],a[2]和a[6],a[3]和a[7],分别解密(最好不要直接copy反编译后的代码,我因为不太熟悉tea加密直接copy,一直没解出来,后来看来wp才理解了,此外a[]数组要设为char型的,我设为int型的也得不到答案,也不知道为啥)
解密代码:
#include <stdio.h>
void Tea(int &v0, int &v1){
// int k[4]={3412,4123,1234,2341};
int sum=-17889239584,i;
int delta=-559038737;
// int k0=k[0],k1=k[1],k2=k[2],k3=k[3];
for(i=0;i<32;i++){
v1-=((v0*16)+3412)^(v0+sum)^((v0*32)+4123);
v0-=((v1*16)+1234)^(v1+sum)^((v1*32)+2341);
sum-=delta;
}
}
int main(){
unsigned char a[] =
{
0x88, 0x6A, 0xB0, 0xC9, 0xAD, 0xF1, 0x33, 0x33, 0x94, 0x74,
0xB5, 0x69, 0x73, 0x5F, 0x30, 0x62, 0x4A, 0x33, 0x63, 0x54,
0x5F, 0x30, 0x72, 0x31, 0x65, 0x6E, 0x54, 0x65, 0x44, 0x3F,
0x21, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int *x = (int*)(a + 3);
int *y = (int*)(a + 7);
Tea( *x, *y );
int* x3=(int*)(a + 2);
int* y3=(int*)(a + 6);
Tea(*x3,*y3);
int* x2=(int*)(a + 1);
int* y2=(int*)(a + 5);
Tea(*x2,*y2);
int* x1=(int*)(a + 0);
int * y1=(int*)(a + 4);
Tea(*x1,*y1);
for(int i=0;i<32;i++)
printf("%c",a[i]);
return 0;
}
void init(int &x){}
:函数接受一个整数类型的引用作为参数,可以直接修改原始变量的值。void init(int *x){}
:函数接受一个指向整数类型的指针作为参数,通过指针可以访问和修改原始变量的值。
答案:hgame{#Cpp_is_0bJ3cT_0r1enTeD?!}
babyre
解题分析:
打开ida,F5反编译main函数,进行分析
sub_1708(a1,a2,a3)函数进行输入flag:
这里注意一下dataextra,它正好在flag后面,就意味着flag[32]=dataextra(说实话我也不太确定)
往下走来到t1的设置,这里注意t1的初始值不是点进去的‘1234’,在main之前t1还有操作(我们交叉引用跟过去)
所以t1=‘feifei’
此外signal(8, handler)这个是C语言中的设置信号处理函数,SIGFPE 8 C 浮点异常 ,而我们看到这段的汇编代码
很明显当i的值为3的时候,会造成除零异常,则跳出循环并执行handler函数,即dataextra++(dataextra=250),所以t1只会异或前3个字符
flag加密过程(PV操作)
sem_init
函数用于创建一个新的信号量并初始化它。信号量是一个用于线程同步的计数器,可以用来解决资源竞争的问题。
代码中使用了 sem_init
函数初始化了四个信号量,并创建了四个线程。其中,四个信号量的初始值分别为 1, 0, 0, 0。创建的四个线程分别执行了不同的函数 start_routine
、sub_140D
、sub_150C
、sub_1609
。
这段代码的作用是通过信号量来实现线程之间的同步,确保线程按照一定的顺序执行。信号量的值为 0 时,线程会被阻塞;信号量的值为1,则线程进行,信号量减1,下一个线程的信号量加1。
所以加密过程即依次循环对flag进行加密操作(加,减,乘,异或)
解密对应反着进行即可
根据sub_1803()函数可知:
加密后的结果为_DWORD data[32] =
{12052,78,20467 ,109, 13016, 109, 27467,-110, 9807,91,21243,-100,11121, 20, 10863, -107, 10490,29, 10633, -101, 10420, 78, 17670, -38, 6011, -4,16590, 125, 10723, 15, 7953, 255};(用这种数据类型存储正好是32个)
_DWORD是无符号长整型,用来表示32位无符号整数,在C语言中为uint32_t类型
需要导入stdint.h模块
解密代码:
#include <stdio.h>
#include <stdint.h>
int main(){
unsigned char t1[] ="feifei";
for ( int i = 0; i <3; ++i )
t1[i]^= 17;
uint32_t data[33] =
{
12052,
78,
20467,
109,
13016,
109,
27467,
-110,
9807,
91,
21243,
-100,
11121,
20,
10863,
-107,
10490,
29,
10633,
-101,
10420,
78,
17670,
-38,
6011,
-4,
16590,
125,
10723,
15,
7953,
255
};
for(int i=31;i>=0;i--){
if(i%4==3)
data[i] ^= data[i + 1] - *((char *)&t1 + (i + 1) % 6);
if(i%4==2)
data[i] /= data[i + 1] + *((char *)&t1 + (i + 1) % 6);
if(i%4==1)
data[i] += *((char *)&t1 + (i + 1) % 6) ^ data[i + 1];
if(i%4==0)
data[i] -= *((char *)&t1 + (i + 1) % 6) * data[i + 1];
}//需要第33个data,即data[32]
for(int i=0;i<32;i++)
printf("%c",data[i]);
return 0;
}
答案:hgame{you_are_3o_c1ever2_3Olve!}
信号量与PV操作https://blog.youkuaiyun.com/bandaoyu/article/details/106693758
babyAndroid
解题分析:
根据文件.apk可以知道是安卓逆向
先使用jdax打开apk文件
jdax使用教程(注意自己下载的版本)https://blog.youkuaiyun.com/gqv2009/article/details/127323557
然后打开MainActivity,分析java代码
这里我们跟入Check1函数,进行分析,很明显是RC4加密(注意MainActivity传入的值,很重要,不要弄错了)
先找一下密钥key
跟入可以看到key
但是但是,这并不是key的值
在Android开发中,通常会使用类似0x7f0f0030
这样的十六进制值来表示资源的ID。在这种情况下,0x7f0f0030
可能是一个资源在R文件中的ID。
所以我们去资源文件里查找key的真正值(key是一个字符串,去字符串里找),key=‘3e1fel’
已知RC4加密后的密文data={-75, 80, 80, 48, -88, 75, 103, 45, -91, 89, -60, 91, -54, 5, 6, -72}
根据RC4解密即可
解密代码:
#include <stdio.h>
#include <string.h>
char key[] = "3e1fel";//长度为6
char data[] = {-75, 80, 80, 48, -88, 75, 103, 45, -91, 89, -60, 91, -54, 5, 6, -72};//长度为16
char S[256];
int main() {
for( int i = 0; i < 256; i ++ ) {
S[i] = i;
}
int p = 0;
char temp;
for( int i = 0; i < 256; i ++ ) {
p = ( p + S[i] + key[ i % 6 ] ) & 255;
temp=S[i];
S[i]=S[p];
S[p]=temp;
}
int p1 = 0, p2 = 0;
for( int i = 0; i < 16; i ++ ) {
p1 =(p1+1)&255;
p2 = ( p2 + S[p1] ) & 255;
temp=S[p1];
S[p1]=S[p2];
S[p2]=temp;
data[i] ^= ( S[ ( S[p1] + S[p2] ) & 255 ] );
}
for( int i = 0; i < 16; i ++ )
printf( "%c", data[i] );
//G>IkH<aHu5FE3GSV
}
这样我们就得到了用户名了,回到MainActivity函数,接着往下看,是check2函数,这里需要注意check2函数是native层
所以需要解压apk,用ida分析so文件(Native层注意JNI_Onload和Java_开头的函数)
扔到IDA中,看不懂了
跟入off_26E8,可以看到我们的check2函数(直接跟入,不用想)
可以看到有个AES,那么肯定就是AES加密了,密文也给出来了(因为是数组大小是32,正好是16的倍数)
也可以使用IDA的插件Findcrypt进行查看,很明显是AES加密
使用CyberChef进行解密即可,前面得到的用户名为密钥(因为用户名正好是16位),因为没有给vi,所以这是AES的ECB模式加密,且不需要填充
(因为在除ECB以外的所有加密方式中,都需要用到IV对加密结果进行随机化)
AES加密https://zhuanlan.zhihu.com/p/131324301
CyberChef https://gchq.github.io/CyberChef/
答案:hgame{df3972d1b09536096cc4dbc5c}
arithmetic
解题分析:
先分析一下文件,发现是upx加壳,但是使用工具进行脱壳失败了,这里扔去WinHex看一下,发现区段名被修改了
手动进行修改,改为55 50 58(upx)
但是这里我只改了两处,其实需要改三个地方
再进行脱壳即可
完,这代码看不太懂了,去看wp了,说是求解数塔问题(我嘞个豆,痛苦啊,看不懂动态规划,直接找的代码),这道题其实就是关于动态规划的最大路径问题(等我能理解动态规划了,我再来补吧)
主要是这里可以看出是求解数塔问题(还有给的out文件,记得改一下扩展名.txt,打开后是一个三角塔一样的数据)v14=1的时候,往左下方走;v14=2的时候,往右下方走
解密代码:(直接网上找的)
#include<iostream>
#include<algorithm>
using namespace std;
int n;
//dp数塔
int a[1000][1000];
//存放着最大路径
int step[1000];
//原数塔
int b[1000][1000];
int main(){
cin >> n;
//读取数塔
for (int i = 0; i < n; i++){
for (int j = 0; j <= i; j++){
cin >> a[i][j];
b[i][j] = a[i][j];
}
}
//计算最大和
for (int i = n - 2; i >= 0; i--){
for (int j = 0; j <= i; j++){
a[i][j] += max(a[i + 1][j], a[i + 1][j + 1]);
}
}
//求最长路径
int x = 0, y = 0;
//根据a数组来求,a数组是已经被修改过的数组,每一层的值是从底层开始求和的最优解
step[0] = b[0][0];
for (int i = 0; i < n - 1; i++){
//若左边大时
if (a[x + 1][y] > a[x + 1][y + 1]){
step[i + 1] = b[x + 1][y];
x++;
cout<<"1";
}
//右边的数据较大时
else{
step[i + 1] = b[x + 1][y + 1];
x++;
y++;
cout<<"2";
}
}
return 0;
}
得到一堆1,2数字串后,根据代码中的
hgame{path_32-bit_md5_lowercase_encrypt},扔去md5加密得到答案
答案:flag{934f7f68145038b3b81482b3d9f3a355}
upx脱壳https://www.52pojie.cn/thread-326995-1-1.html
去upx特征 https://blog.youkuaiyun.com/whatday/article/details/99709317
动态规划 https://blog.youkuaiyun.com/TheJormangund/article/details/110259842
CRYPTO
midRSA
尝试了一下m0,得到flag(属实没想到,其实考察的是sage高位攻击)
n=120838778421252867808799302603972821425274682456261749029016472234934876266617266346399909705742862458970575637664059189613618956880430078774892479256301209695323302787221508556481196281420676074116272495278097275927604857336484564777404497914572606299810384987412594844071935546690819906920254004045391585427
c=118961547254465282603128910126369011072248057317653811110746611348016137361383017921465395766977129601435508590006599755740818071303929227578504412967513468921191689357367045286190040251695094706564443721393216185563727951256414649625597950957960429709583109707961019498084511008637686004730015209939219983527
m0=13292147408567087351580732082961640130543313742210409432471625281702327748963274496942276607
print(long_to_bytes(m0))
答案:hgame{0ther_cas3s_0f_c0ppr3smith}
midRSA revenge
已知m的高位,sage高位攻击
RSA已知高位攻击https://blog.youkuaiyun.com/m0_57291352/article/details/120675242
sage脚本_m高位攻击https://www.bilibili.com/read/cv13467999/
Coppersmith 攻击定理https://xie-yuanhao.gitee.io/2022/02/24/Crypto-RSA-Coppersmith%E6%94%BB%E5%87%BB/
sage在线网站https://sagecell.sagemath.org/
sage代码
n=27814334728135671995890378154778822687713875269624843122353458059697288888640572922486287556431241786461159513236128914176680497775619694684903498070577307810263677280294114135929708745988406963307279767028969515305895207028282193547356414827419008393701158467818535109517213088920890236300281646288761697842280633285355376389468360033584102258243058885174812018295460196515483819254913183079496947309574392848378504246991546781252139861876509894476420525317251695953355755164789878602945615879965709871975770823484418665634050103852564819575756950047691205355599004786541600213204423145854859214897431430282333052121
c=456221314115867088638207203034494636244706611111621723577848729096069230067958132663018625661447131501758684502639383208332844681939698124459188571813527149772292464139530736717619741704945926075632064072125361516435631121845753186559297993355270779818057702973783391589851159114029310296551701456748698914231344835187917559305440269560613326893204748127999254902102919605370363889581136724164096879573173870280806620454087466970358998654736755257023225078147018537101
high_m=3402789736593180236658155503802934243882633217001276110456412540082077704313307856114886377472
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
m = high_m + x
M = m((m**e - c).small_roots()[0])
print(long_to_bytes(int(M)))
m0要进行还原位数,即(m0>>128)<<128
答案:hgame{c0ppr3smith_St3re0typed_m3ssag3s}
backpack
题目:
from Crypto.Util.number import *
import random
from secret import flag
a=[getPrime(32) for _ in range(20)]#生成20个素数
p=random.getrandbits(32)#随机生成一个32位的整数
assert len(bin(p)[2:])==32
bag=0
for i in a:
temp=p%2
bag+=temp*i
p=p>>1
enc=bytes_to_long(flag)^p
print(f'enc={enc}')
print(f'a={a}')
print(f'bag={bag}')
"""
enc=871114172567853490297478570113449366988793760172844644007566824913350088148162949968812541218339
a=[3245882327, 3130355629, 2432460301, 3249504299, 3762436129, 3056281051, 3484499099, 2830291609, 3349739489, 2847095593, 3532332619, 2406839203, 4056647633, 3204059951, 3795219419, 3240880339, 2668368499, 4227862747, 2939444527, 3375243559]
bag=45893025064
"""
很明显根据题目可以知道是背包加密,但是我不会
但是问题也不大,题目中flag与p异或得到enc,而p是一个32位(二进制位数)的整数,那么p的范围肯定不会很大,我们可以直接爆破得到答案
解题代码:
print(2**31)
//2147483648
enc=871114172567853490297478570113449366988793760172844644007566824913350088148162949968812541218339
for i in range(2147483648):
flag=enc^i
if b'hgame' in long_to_bytes(flag):
print(long_to_bytes(flag))
break
答案:hgame{M@ster_0f ba3kpack_m4nag3ment!}
backpack revenge
题目:
from Crypto.Util.number import *
import random
import hashlib
a=[getPrime(96) for _ in range(48)]
p=random.getrandbits(48)
assert len(bin(p)[2:])==48
flag='hgame{'+hashlib.sha256(str(p).encode()).hexdigest()+'}'
bag=0
for i in a:
temp=p%2
bag+=temp*i
p=p>>1
print(f'a={a}')
print(f'bag={bag}')
"""
a=[74763079510261699126345525979, 51725049470068950810478487507, 47190309269514609005045330671, 64955989640650139818348214927, 68559937238623623619114065917, 72311339170112185401496867001, 70817336064254781640273354039, 70538108826539785774361605309, 43782530942481865621293381023, 58234328186578036291057066237, 68808271265478858570126916949, 61660200470938153836045483887, 63270726981851544620359231307, 42904776486697691669639929229, 41545637201787531637427603339, 74012839055649891397172870891, 56943794795641260674953676827, 51737391902187759188078687453, 49264368999561659986182883907, 60044221237387104054597861973, 63847046350260520761043687817, 62128146699582180779013983561, 65109313423212852647930299981, 66825635869831731092684039351, 67763265147791272083780752327, 61167844083999179669702601647, 55116015927868756859007961943, 52344488518055672082280377551, 52375877891942312320031803919, 69659035941564119291640404791, 52563282085178646767814382889, 56810627312286420494109192029, 49755877799006889063882566549, 43858901672451756754474845193, 67923743615154983291145624523, 51689455514728547423995162637, 67480131151707155672527583321, 59396212248330580072184648071, 63410528875220489799475249207, 48011409288550880229280578149, 62561969260391132956818285937, 44826158664283779410330615971, 70446218759976239947751162051, 56509847379836600033501942537, 50154287971179831355068443153, 49060507116095861174971467149, 54236848294299624632160521071, 64186626428974976108467196869]
bag=1202548196826013899006527314947
"""
解题分析:
背包加密原理 https://www.ruanx.net/lattice-2/
我们的背包密码其实也就是子集和问题
解密方法:
用sage构造出一个格(矩阵),然后使用LLL算法进行格基规约即可,得到的结果的第一行的相反向量就是我们要求的解(具体原理说实话不是很懂)
解题代码:
在sagemath中
M=[74763079510261699126345525979, 51725049470068950810478487507, 47190309269514609005045330671, 64955989640650139818348214927, 68559937238623623619114065917, 72311339170112185401496867001, 70817336064254781640273354039, 70538108826539785774361605309, 43782530942481865621293381023, 58234328186578036291057066237, 68808271265478858570126916949, 61660200470938153836045483887, 63270726981851544620359231307, 42904776486697691669639929229, 41545637201787531637427603339, 74012839055649891397172870891, 56943794795641260674953676827, 51737391902187759188078687453, 49264368999561659986182883907, 60044221237387104054597861973, 63847046350260520761043687817, 62128146699582180779013983561, 65109313423212852647930299981, 66825635869831731092684039351, 67763265147791272083780752327, 61167844083999179669702601647, 55116015927868756859007961943, 52344488518055672082280377551, 52375877891942312320031803919, 69659035941564119291640404791, 52563282085178646767814382889, 56810627312286420494109192029, 49755877799006889063882566549, 43858901672451756754474845193, 67923743615154983291145624523, 51689455514728547423995162637, 67480131151707155672527583321, 59396212248330580072184648071, 63410528875220489799475249207, 48011409288550880229280578149, 62561969260391132956818285937, 44826158664283779410330615971, 70446218759976239947751162051, 56509847379836600033501942537, 50154287971179831355068443153, 49060507116095861174971467149, 54236848294299624632160521071, 64186626428974976108467196869]
S=1202548196826013899006527314947
n = len(M)
L = matrix.zero(n + 1)
for row, x in enumerate(M):
L[row, row] = 2
L[row, -1] = x
L[-1, :] = 1
L[-1, -1] = S
res = L.LLL()
print(res)
python
import hashlib
a="1 -1 -1 -1 -1 1 -1 -1 1 -1 -1 -1 1 1 1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 -1 -1 1 -1 1 -1 1 -1 1 1 -1 1 -1 -1 -1 -1 1 -1 1 1 1 1"
list1=list(a.split(" "))
print(len(list1))#48
p=''
for i in list1:
if i=='1':
p+='0'
else:
p+='1'
print(p)
flag='hgame{'+hashlib.sha256(str(p).encode()).hexdigest()+'}'
print(flag)
答案:
hgame{ffeb545d678a2731c7d5131b2d798ea1e52847dc61525d022b107d9cd619091d}
babyRSA
开n次方根https://blog.youkuaiyun.com/jcbx_/article/details/105303760
gift=pow(e+114514+p**k,0x10001,p)
对于这个直接按照解RSA的解法解,可以得到e+114514+p**k=188075
则e+p**k=73561
因为p比73561还要大,则e=73561
(或者换个角度,pow(e+114514+p**k,0x10001,p)=pow(e+114514,0x10001,p),这里面涉及到的是简单的模运算)
这里解出了e但是phi与e不互素,之前只学过简单的处理方法,而这里phi是e的整数倍,不适用于之前学过的方法,需要用到AMM算法(纯手搓AMM算法对不起我做不到啊,这里用sagemath的相关集成运算,sagemath我的神)
解密代码:
sage
from Crypto.Util.number import *
p=14213355454944773291
q=61843562051620700386348551175371930486064978441159200765618339743764001033297
c=105002138722466946495936638656038214000043475751639025085255113965088749272461906892586616250264922348192496597986452786281151156436229574065193965422841
gift=9751789326354522940
e = 73561
v = Zmod(p*q)(c).nth_root(e, all=True)#这里直接求出m^e%(p*q)=c的解,即m的值,但需要筛选
for i in v:
m = long_to_bytes(int(i))
if b'hgame' in m:
print(m)
break
答案:hgame{Ad1eman_Mand3r_Mi11er_M3th0d}
奇怪的图片plus
这道题真的不懂了(wp都看不懂),触及我知识盲区了