предисловие
Реализация инструментов аудита кода - это все инструменты, разработанные на основе опыта аудита кода для оптимизации эффективности работы.Если мы хотим хорошо изучить аудит кода, мы должны быть знакомы с идеей аудита кода. Аудит кода основан на языке PHP.Самое основное требование для изучения аудита кода — уметь читать и понимать код.
Существует четыре общих идеи аудита кода:
Откат процесса передачи параметров на основе конфиденциальных ключевых слов; Найдите контролируемые переменные и отследите процесс передачи переменных вперед; Найдите чувствительные функциональные точки и прочитайте коды функциональных точек; Прочитайте полный текстовый код напрямую. Процедура параметра обратного отслеживания чувствительной функции Обратное отслеживание процесса передачи параметров на основе конфиденциальных функций в настоящее время является наиболее часто используемым методом, поскольку большинство уязвимостей вызвано неправильным использованием функций. Кроме того, уязвимости неправильного использования не-функций, таких как SQL-инъекция, будут подробно описаны позже. Преимущества и недостатки этого метода следующие:
Преимущества: Просто найдите соответствующие чувствительные ключевые слова, вы можете быстро выкопать нужные лазейки, направленный майнинг, эффективный и качественный; Недостатки: Из-за отсутствия тщательного чтения кода понимание общей структуры программы недостаточно глубокое, поиск и эксплуатация уязвимостей займет некоторое время, а логика майнинга уязвимостей не может быть покрыта. Инъекционный майнинг espcms:
URL-адрес загрузки:http://down.chinaz.com/soft/27695.htm
Загрузите исходную программу espcms (ps: исходники некоторых программ можно скачать на chinaz.com) Откройте систему аудита исходного кода Seay, щелкните новый проект в левом верхнем углу, выберите загруженную папку espcms, нажмите Auto Audit, запустите аудит и получите возможные уязвимости, путь к файлу уязвимости и список уязвимостей. коды.
Выбираем один из кодов
Дважды щелкните непосредственно, чтобы найти эту строку кода, после выбора переменной вы можете увидеть процесс передачи переменной, щелкните слеваПолучена переменная parentid.
Щелкните правой кнопкой мыши, чтобы выбрать эту строку кода, найдите тело функции, щелкните правой кнопкой мыши и выберите функцию поиска.
Вы можете видеть, что переход к файлу class_function.php выглядит следующим образом:
Видно, что это функция для получения значения параметров GET, POST и COOKIE. Переменные, которые мы передаем, — это parentid и R, что означает, что параметр parentid может быть получен в POST и GET. Наконец, после слэша (), на самом деле это обернутая функция addlashes() для фильтрации символов, таких как одинарные кавычки. Посмотрите на предыдущую инструкцию SQL следующим образом:db_table, где parentid=$parentid"; Для закрытия не нужны одинарные кавычки, его можно вставить напрямую.
В файле citylist.php вы можете видеть, что функция oncitylist() находится в важном классе, выберите имя класса, щелкните правой кнопкой мыши и выберите «Глобальный поиск». Вы можете видеть, что файл index.php создал экземпляр этого класса, и код выглядит следующим образом:
$archive = indexget(‘archive’, ‘R’);
$archive = empty($archive) ? ‘adminuser’ : $archive;
$action = indexget(‘action’, ‘R’);
$action = empty($action) ? ‘login’ : $action;
$soft_MOD = array(‘admin’, ‘public’, ‘product’, ‘forum’, ‘filemanage’, ‘basebook’, ‘member’, ‘order’, ‘other’, ‘news’, ‘inc’, ‘cache’, ‘bann’, ‘logs’, ‘template’);
if (in_array($point, $soft_MOD)) {
include admin_ROOT . adminfile . “/control/$archive.php”;
$control = new important();
$action = ‘on’ . $action;
if (method_exists($control, $action)) {
$control->$action();
} else {
exit(‘错误:系统方法错误!’);
}
Здесь вы можете увидеть работу включаемого файла.К сожалению, после того, как функция addlashes() не может быть выполнена, он может содержать любой файл, только локальные файлы PHP.Следующим шагом является создание экземпляра класса и вызов функции, которую можно построен в соответствии с кодом.Чтобы использовать EXP:
http://127.0.0.1/espcms/upload/adminsoft/index.php?archive=citylist&action=citylist&parentid=-1 union select 1,2,user(),4,5
Прочитать полный текст кода Есть определенные навыки чтения полнотекстового кода, иначе сложно читать веб-программу, а также сложно понять бизнес-логику кода. Прежде всего, нам нужно посмотреть на общую структуру программы, например, какие файлы находятся в основном каталоге, какие файлы находятся в каталоге модуля, а какие файлы находятся в каталоге плагинов. обратите внимание на размер файлов и время создания, чтобы мы могли примерно знать, какие функции реализовала эта программа.
Например, основной каталог diskuz показан на следующем рисунке:
При просмотре структуры каталогов обратите особое внимание на следующие файлы:
- файл набора функций
Файлы наборов функций обычно содержат ключевые слова, такие как функции или общие в их именах.Эти файлы содержат некоторые общедоступные функции, которые предоставляются другим файлам для унифицированного вызова, поэтому большинство файлов будут включены в заголовок файла для других файлов. Чтобы найти эти файлы, нужно открыть index.php или другой функциональный файл.
- конфигурационный файл
Файл конфигурации обычно содержит ключевое слово config в имени, а файл конфигурации включает функциональные параметры конфигурации, необходимые для запуска веб-программы, и информацию о конфигурации, такую как база данных. Из этого файла можно понять небольшую часть работы программы.Кроме того, при просмотре этого файла обратите внимание на то, в одинарных или двойных кавычках указаны параметры в конфигурационном файле.Если это двойные кавычки , могут быть уязвимости выполнения кода.
- Безопасная фильтрация файлов
Файлы фильтрации безопасности очень важны для аудита кода. Обычно в названии есть такие ключевые слова, как filter, safe, check. Эти файлы в основном используются для фильтрации параметров. а также пути к файлам. , параметры выполняемой системной команды.
- индексный файл
Индекс — это входной файл программы, поэтому нам нужно прочитать индексный файл только один раз, чтобы получить общее представление о структуре всей программы, выполняемом процессе и включенных файлах.
Knight CMS прочитал аудиторский кейс (1) Просмотр файловой структуры приложения
Во-первых, посмотрите, какие файлы и папки существуют, и найдите файлы и папки с такими ключевыми словами, как api, admin, manage и include в их именах. Вы можете видеть, что есть папка include, обычно основные файлы будут помещены в эту папку.
(2) Просмотр кода файла ключа В этой папке вы можете увидеть десятки файлов K. Слабый файл common.fun.php является основным файлом этой программы, и основные функции в основном реализованы в этом файле. Как только я открываю файл, я сразу вижу множество функций фильтрации, первая из которых — функция фильтрации SQL-инъекций:
function addslashes_deep($value)
{
if (empty($value))
{
return $value;
}
else
{
if (!get_magic_quotes_gpc())
{
$value=is_array($value) ? array_map(‘addslashes_deep’, $value) : mystrip_tags(addslashes($value));
}
else
{
$value=is_array($value) ? array_map(‘addslashes_deep’, $value) : mystrip_tags($value);
}
return $value;
}
}
Эта функция использует функцию addlashes() для фильтрации входящих переменных, отфильтровывая одинарные и двойные кавычки, символы NULL и косые черты. Внедрение широких байтов или другие особые случаи, внедрение с помощью этой функции невозможно.
Ниже находится функция фильтрации XSS mystrip_tags(), код которой выглядит следующим образом:
function mystrip_tags($string)
{
$string = new_html_special_chars($string);
$string = remove_xss($string);
return $string;
}
Эта функция вызывает функции new_html_special_chars() и remove_xss() для фильтрации XSS, код выглядит следующим образом:
function new_html_special_chars($string) {
$string = str_replace(array(‘&’, ‘"’, ‘<’, ‘>’), array(‘&’, ‘“‘, ‘<’, ‘>’), $string);
$string = strip_tags($string);
return $string;
}
function remove_xss($string) {
$string = preg_replace(‘/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S’, ‘’, $string);
$parm1 = Array('javascript', 'union','vbscript', 'expression', 'applet', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
$parm2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload','style','href','action','location','background','src','poster');
$parm3 = Array('alert','sleep','load_file','confirm','prompt','benchmark','select','update','insert','delete','alter','drop','truncate','script','eval','outfile','dumpfile');
$parm = array_merge($parm1, $parm2, $parm3);
for ($i = 0; $i < sizeof($parm); $i++) {
$pattern = '/';
for ($j = 0; $j < strlen($parm[$i]); $j++) {
if ($j > 0) {
$pattern .= '(';
$pattern .= '(&#[x|X]0([9][a][b]);?)?';
$pattern .= '|(�([9][10][13]);?)?';
$pattern .= ')?';
}
$pattern .= $parm[$i][$j];
}
$pattern .= '/i';
$string = preg_replace($pattern, '****', $string);
}
return $string;
}
Как вы можете видеть в функции new_html_special_chars(), эта функция кодирует html-объект амперсанда, двойных кавычек и угловых скобок и использует функцию strip_tags() для вторичной фильтрации. Функция remove_xss() заменяет некоторые ключевые слова тегов, ключевые слова событий и ключевые слова конфиденциальных функций.
Далее есть функция getip() для получения IP-адреса, которая может подделывать IP-адреса:
function getip()
{
if (getenv(‘HTTP_CLIENT_IP’) and strcasecmp(getenv(‘HTTP_CLIENT_IP’),’unknown’)) {
$onlineip=getenv(‘HTTP_CLIENT_IP’);
}elseif (getenv(‘HTTP_X_FORWARDED_FOR’) and strcasecmp(getenv(‘HTTP_X_FORWARDED_FOR’),’unknown’)) {
$onlineip=getenv(‘HTTP_X_FORWARDED_FOR’);
}elseif (getenv(‘REMOTE_ADDR’) and strcasecmp(getenv(‘REMOTE_ADDR’),’unknown’)) {
$onlineip=getenv(‘REMOTE_ADDR’);
}elseif (isset($_SERVER[‘REMOTE_ADDR’]) and $_SERVER[‘REMOTE_ADDR’] and strcasecmp($_SERVER[‘REMOTE_ADDR’],’unknown’)) {
$onlineip=$_SERVER[‘REMOTE_ADDR’];
}
preg_match(“/\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}/“,$onlineip,$match);
return $onlineip = $match[0] ? $match[0] : ‘unknown’;
}
Многие приложения будут иметь уязвимости внедрения, потому что они не проверяют формат IP при получении IP, но здесь возможно только подделать IP.
Ниже вы можете увидеть место, достойное внимания, унифицированную функцию работы функции SQL-запроса inserttable() и updatetable(), здесь будет проходить большая часть выполнения оператора SQL, поэтому мы должны обратить внимание на то, есть ли проблемы, такие как фильтрация в этом месте.
function inserttable($tablename, $insertsqlarr, $returnid=0, $replace = false, $silent=0) {
global $db;
$insertkeysql = $insertvaluesql = $comma = ‘’;
foreach ($insertsqlarr as $insert_key => $insert_value) {
$insertkeysql .= $comma.’'.$insert_key.'‘;
$insertvaluesql .= $comma.’\’’.$insert_value.’\’’;
$comma = ‘, ‘;
}
$method = $replace?’REPLACE’:’INSERT’;
// echo $method.” INTO $tablename ($insertkeysql) VALUES ($insertvaluesql)”, $silent?’SILENT’:’’;die;
$state = $db->query($method.” INTO $tablename ($insertkeysql) VALUES ($insertvaluesql)”, $silent?’SILENT’:’’);
if($returnid && !$replace) {
return $db->insert_id();
}else {
return $state;
}
}
Ниже находится функция wheresql(), в которую вставляется условие запроса запроса SQL. Мы видим, что параметры заключены в одинарные кавычки. Код выглядит следующим образом:
function wheresql($wherearr=’’)
{
$wheresql=””;
if (is_array($wherearr))
{
$where_set=’ WHERE ‘;
foreach ($wherearr as $key => $value)
{
$wheresql .=$where_set. $comma.$key.’=”‘.$value.’”‘;
$comma = ‘ AND ‘;
$where_set=’ ‘;
}
}
return $wheresql;
}
Существует также функция генерации токена доступа asyn_userkey(), которая объединяет имя пользователя, соль пароля и пароль для выполнения md 5. При доступе вам нужно только добавить сгенерированный ключ к значению параметра GET, чтобы проверить, есть ли у вас разрешение , В процессе проверки, такой как регистрация и получение пароля, код выглядит следующим образом:
function asyn_userkey($uid)
{
global $db;
$sql = “select * from “.table(‘members’).” where uid = ‘“.intval($uid).”‘ LIMIT 1”;
$user=$db->getone($sql);
return md5($user[‘username’].$user[‘pwd_hash’].$user[‘password’]);
}
(3) Просмотрите файл конфигурации Выше мы говорили, что файл конфигурации обычно имеет ключевое слово, такое как «config», нам просто нужно найти имя файла с этим ключевым словом:
В результатах поиска мы видим, что было найдено несколько файлов. В сочетании с опытом мы можем судить, что config.php и cache_config.php являются реальными файлами конфигурации. Откройте config.php, чтобы просмотреть код:
<?php
$dbhost = “localhost”;
$dbname =”74cms”;
$dbuser =”root”;
$dbpass =”123456”;
$pre =”qs_”;
$QS_cookiedomain = ‘’;
$QS_cookiepath = “/74cms/“;
$QS_pwdhash = “K0ciF:RkE4xNhu@S”;
define(‘QISHI_CHARSET’,’gb2312’);
define(‘QISHI_DBCHARSET’,’GBK’);
?>
Очевидно, что очень вероятно, что существует проблема с выполнением кода разбора двойных кавычек, о котором мы упоминали ранее.Обычно эта конфигурация задается при установке системы или есть место для ее установки в фоновом режиме.
Посмотрите на код, установленный при подключении базы данных, и найдите код для knight cms для подключения к MySQL в функции connect() файла include\mysql.class.php Код выглядит следующим образом:
function connect($dbhost, $dbuser, $dbpw, $dbname = ‘’, $dbcharset = ‘gbk’, $connect=1){
$func = empty($connect) ? ‘mysql_pconnect’ : ‘mysql_connect’;
if(!$this->linkid = @$func($dbhost, $dbuser, $dbpw, true)){
$this->dbshow(‘Can not connect to Mysql!’);
} else {
if($this->dbversion() > ‘4.1’){
mysql_query( “SET NAMES gbk”);
if($this->dbversion() > ‘5.0.1’){
mysql_query(“SET sql_mode = ‘’”,$this->linkid);
mysql_query(“SET character_set_connection=”.$dbcharset.”, character_set_results=”.$dbcharset.”, character_set_client=binary”, $this->linkid);
}
}
}
if($dbname){
if(mysql_select_db($dbname, $this->linkid)===false){
$this->dbshow(“Can’t select MySQL database($dbname)!”);
}
}
}
В этом коде есть ключевое место, представляющее угрозу безопасности.
Сначала код определяет, больше ли версия MySQL 4.1, и если да, то выполняет следующий код:mysql_query( “SET NAMES gbk”);
После выполнения этого оператора считается, что если версия больше 5, выполняется следующий код:mysql_query(“SET character_set_connection=”.$dbcharset.”, character_set_results=”.$dbcharset.”, character_set_client=binary”, $this->linkid);
То есть эта строка кода не будет выполняться, если версия MySQL меньше 5.
Но после выполнения «setnames gbk» мы ввели «setnames gbk», прежде чем он на самом деле сделает три вещи, которые эквивалентны:SET character_set_connection=’gbk’, character_set_results=’gbk’, character_set_client=’gbk’
Поэтому, когда версия MySQL больше 4.1 и меньше 5, в основном все операции, связанные с базой данных, имеют широкое внедрение байтов.
(4) Следите за документом на главной странице Благодаря общему пониманию системных файлов наша команда имеет определенное представление об общей структуре этой программы, но этого недостаточно.Нам нужно прочитать файл index.php и посмотреть, какие файлы и функции вызываются при запуске программы. Бег.
Откройте файл домашней страницы index.php, и вы увидите следующий код:
if(!file_exists(dirname(FILE).’/data/install.lock’))
header(“Location:install/index.php”);
define(‘IN_QISHI’, true);
$alias=”QS_index”;
require_once(dirname(FILE).’/include/common.inc.php’);
Сначала определите, существует ли файл блокировки установки, если нет, перейдите к install\index.php
Следующим шагом является включение файла \include\common.inc.php, просмотр файла
require_once(QISHI_ROOT_PATH.’data/config.php’);
header(“Content-Type:text/html;charset=”.QISHI_CHARSET);
require_once(QISHI_ROOT_PATH.’include/common.fun.php’);
require_once(QISHI_ROOT_PATH.’include/74cms_version.php’);
Файл \include\common.inc.php содержит в начале три файла: data\config.php — файл конфигурации базы данных, include\common.fun.php — файл базовой библиотеки функций, а include\74cms_version.php — файл конфигурации базы данных. файл версии приложения.
Посмотрите еще раз на следующий код:
f (!empty($_GET))
{
$_GET = addslashes_deep($_GET);
}
if (!empty($_POST))
{
$_POST = addslashes_deep($_POST);
}
$_COOKIE = addslashes_deep($_COOKIE);
$_REQUEST = addslashes_deep($_REQUEST);
Этот код вызывает функцию addlashes_deep() в файле include\common.fun.php для фильтрации параметров GET, POST, COOKIE.
Ниже вы можете увидеть, что есть операция, которая включает файл:require_once(QISHI_ROOT_PATH.’include/tpl.inc.php’);
Включите файл include\tpl.inc.php, перейдите по этому файлу, чтобы увидеть:
include_once(QISHI_ROOT_PATH.’include/template_lite/class.template.php’);
$smarty = new Template_Lite;
$smarty -> cache_dir = QISHI_ROOT_PATH.’temp/caches/‘.$_CFG[‘template_dir’];
$smarty -> compile_dir = QISHI_ROOT_PATH.’temp/templates_c/‘.$_CFG[‘template_dir’];
$smarty -> template_dir = QISHI_ROOT_PATH.’templates/‘.$_CFG[‘template_dir’];
$smarty -> reserved_template_varname = “smarty”;
$smarty -> left_delimiter = “”;
$smarty -> force_compile = false;
$smarty -> assign(‘_PLUG’, $_PLUG);
$smarty -> assign(‘QISHI’, $_CFG);
$smarty -> assign(‘page_select’,$page_select);
Прежде всего, мы видим, что включен файл include\template_lite\class.template.php, который представляет собой класс, отображающий шаблон программы.Если вы продолжите смотреть вниз, вы увидите, что этот код создает экземпляр этого объекта класса и присваивает в переменную ¥smarty.
Продолжайте следить и вернитесь к коду файла index.php:
if(!$smarty->is_cached($mypage[‘tpl’],$cached_id))
{
require_once(QISHI_ROOT_PATH.’include/mysql.class.php’);
$db = new mysql($dbhost,$dbuser,$dbpass,$dbname);
unset($dbhost,$dbuser,$dbpass,$dbname);
$smarty->display($mypage[‘tpl’],$cached_id);
}
else
{
$smarty->display($mypage[‘tpl’],$cached_id);
}
Определите, была ли она кэширована, а затем вызовите функцию display() для вывода страницы. Затем следуйте другим файлам ввода функций, таким как аудит файла index.php, чтобы завершить чтение кода.
Целевой аудит на основе функциональных точек Опираясь на опыт, кратко представим уязвимости, которые появятся в нескольких функциональных точках:
- Функция загрузки файлов
Упомянутая здесь загрузка файлов появится во многих функциональных пунктах, таких как редактирование статей, редактирование данных, загрузка аватаров и загрузка вложений.Наиболее распространенной уязвимостью в этой функции является загрузка произвольных файлов.Вспомогательная программа строго не ограничивает формат загрузки, в результате чего его можно загрузить или обойти, и в дополнение к функции загрузки файлов часто возникают уязвимости SQL-инъекций.
- Функция управления файлами
В функции управления файлами, если программа передает имя файла или путь к файлу непосредственно в параметрах, очень вероятно, что в произвольных файлах будут лазейки в операциях, такие как чтение произвольного файла и т. д. Метод эксплуатации заключается в использовании ../ в пути или ..\перейти в каталог. В дополнение к произвольным уязвимостям файловых операций также могут быть уязвимости XSS, программа выводит имя файла на странице, но обычно пренебрегает фильтрацией имени файла, в результате чего имя файла может быть сохранено со специальными символами, такими как угловые скобки. в базе данных, которая, наконец, будет выполнена при отображении страницы.
- Функция аутентификации входа
Функция аутентификации при входе относится не к процессу, а к аутентификации всего рабочего процесса.Большинство текущих методов аутентификации основаны на файлах cookie и сеансах.Многие программы помещают информацию аутентификации, такую как текущая учетная запись пользователя, в файлы cookie. , который может быть зашифрован. Когда операция выполняется, текущая информация о пользователе считывается непосредственно из файла cookie.Есть проблема в том, что алгоритм заслуживает доверия.Если информация файла cookie не добавляется с чем-то вроде соли, это может привести к любой уязвимости при входе пользователя.Вы можете генерировать токен аутентификации, читая информацию, и даже некоторые программы будут напрямую помещать имя пользователя в файл cookie и напрямую считывать данные имени пользователя во время работы.
- Функция восстановления пароля
Хотя восстановление пароля не выглядит уязвимостью, которая может поставить под угрозу безопасность сервера, например загрузку произвольных файлов, если вы можете сбросить пароль администратора, вы также можете косвенно контролировать бизнес-разрешения и даже получать разрешения на обслуживание. Существует множество сценариев эксплуатации уязвимости функции восстановления пароля, наиболее распространенным из которых является подрыв проверочного кода. В настоящее время, особенно в приложениях APP, при запросе внутренних кодов подтверждения большинство из них состоят из 4 цифр, и нет ограничений на количество ошибок и время действия кодов подтверждения, поэтому существует лазейка.