HGAME week2复现

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_routinesub_140Dsub_150Csub_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/

Knapsack背包密码常见攻击方法https://ohmygodlin.github.io/ctf/crypto/2020/06/18/Knapsack%E8%83%8C%E5%8C%85%E5%AF%86%E7%A0%81%E5%B8%B8%E8%A7%81%E6%94%BB%E5%87%BB%E6%96%B9%E6%B3%95/

在这里插入图片描述

我们的背包密码其实也就是子集和问题

解密方法:

用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都看不懂),触及我知识盲区了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值