07WDDMZXFZ9TXL1什么修改手机型号号

PHP邮件注入攻击技术(1)
如今,互联网的使用急剧上升,但绝大多数互联网用户没有安全知识背景。大多数的人都会使用互联网通过邮件Email的方式和他人进行通信。出于这个 原因,大 多数网站允许他们的用户联系他们,向网站提供建议,报告一个问题,或者要求反馈,用户将会发送反馈给网站管理员的电子邮件。
不 幸的是,大多数web开发人员对安全编码Code-Security没有足够的认识,其中的一些程序猿使用现成的库或框架,这些库受到许多已知的。这 些漏洞是已经公布,厂商并已经对其进行了修补,并且相应的攻击源代码poc都在互联网上可下载的,但大多数开发人员都懒得升级到最新版本。
今天我们要谈论电子邮件注射,攻击者可以使用你的邮件服务器来发送垃圾邮件。
2. 邮件注入
From Wikipedia:
电子邮件注入是一个安全漏洞,这种漏洞广泛存在于在互联网电子邮件收发应用中。这是电子邮件注射和HTTP头注射类似。和SQL注入攻击类似,这种漏洞是一类常见的的漏洞,发生在当一个语言是嵌入到另一个,例如MYSQL嵌入到中。
当一个可以提交数据到一个Web应用程序表单被添加到一个Web页面,恶意用户可能会利用MIME格式添加额外的信息到要发送的消息中 (POST/GET),比如一个新的收件人列表或一个完全不同的消息体。因为MIME格式使用回车分隔在数据包中信息(HTTP数据包中的每一行之间都有 一个换行符,在POST和HTTP HEADER之间有两个换行符),通过添加回车提交表单数据(使用FB的一些插件可以很容易的做到),可以允许一个简单的留言板是用来发送成千上万的消 息。同样,一个垃圾邮件发送者可以使用这种战术的恶意发送大量的匿名消息。
电子邮件注入是针对PHP内置邮件功能的一种攻击类型。它允许恶意攻击者注入任何邮件头字段,BCC、CC、主题等,它允许通过注入手段从受害 者的邮 件服务器发送垃圾邮件。由于这个原因,这种攻击称为电子邮件注入,或者邮件形式滥发。这个漏洞是不限于PHP。它可能会影响任何从用户UI接收消息并发送 电子邮件消息的应用程序。这种攻击的主要原因是不适当的用户输入验证或应用程序根本没有验证和过滤机制。
3. 邮件注入的攻击原理
中国古话说得好: 知其然才能知其所以然。
为了解释邮件注入的工作原理,我们必须先了解PHP Email函数的工作原理。下面是从PHP Manual中找到API解释
bool&mail&(&string&$to&,&string&$subject&,&string&$message&[,&string&$additional_headers&[,&string&$additional_parameters&]]&)&
你可以注意到,这需要三个必填参数(&目的地、主题和消息&)和其他一些可选参数和函数返回一个布尔值。
那么让我们来看看一个带漏洞的代码来演示这个漏洞:
&if&(!isset($_POST[&send&]))&
&&&&form&method=&POST&&action=&&?php&echo&$_SERVER['PHP_SELF'];?&&&&
&&&From:&&input&type=&text&&name=&sender&&&
&&&Subject&:&&input&type=&text&&name=&subject&&&
&&&Message&:&
&&&&textarea&name=&message&&rows=&10&&cols=&60&&lines=&20&&&/textarea&&
&&&&input&type=&submit&&name=&send&&value=&Send&&&
&&&&/form&&
&&&$from=$_POST['sender'];&
&&&if&(mail($to,$_POST['subject'],$_POST['message'],&From:&$fromn&))&
&&&&&echo&&Your&mail&has&been&sent&successfully&;&
&&&&&echo&&An&error&has&been&occured&!&;&
前面的代码将用于演示目的和解释我们的攻击原理。我们将前面的代码分成三个部分:
&if&(!isset($_POST[&send&])){&
这段代码将检查表单提交或不是。用户点击提交按钮和普通访问这个页面脚本的响应将是不同的, 如果这段代码返回True(if语句中的判断最终结果为true)这意味着表单没有提交。表单将出现,等待用户输入。另一方面,如果它返 回&False&,这意味着表单已经提交,所以电子邮件将被发送。
&method=&POST&&action=&&?echo&$_SERVER['PHP_SELF'];?&&&
&From:&&type=&text&&name=&sender&&
&Subject&:&&type=&text&&name=&subject&&
&Message&:&
&&name=&message&&rows=&10&&cols=&60&&lines=&20&&
&&type=&submit&&name=&send&&value=&Send&&
第二部分是一个HTML表单标记,这要求用户输入。
&&&$from=$_POST['sender'];&
&&&if&(mail($to,$_POST['subject'],$_POST['message'],&From:&$fromn&))&
&&&&&echo&&Your&mail&has&been&sent&successfully&;&
&&&&&echo&&An&error&has&been&occured&!&;&
在前面的代码中我们可以特别注意这一行 mail($to,$_POST['subject'],$_POST['message'],&From: $fromn&), PHP的mail()函数需要subject, message, from 这些参数。如果函数执行成功,由PHP引擎发送邮件后,将打印出成功提示 &Your mail has been sent successfully&。如果出现错误,将提示相应信息 &An error has been occurred
但是有朋友要问了,问题在哪里?主要的问题对用户的输入没有做必要的验证和过滤,正如《白帽子讲web安全》里说到的,任何的安全问题可以归结为信 任的问 题,这里存在的问题就是程序代码对用户的输入无限制的信任。正如你所看到的在第三部分代码,发送邮件功能代码从用户接收输入(包括邮件主题、消息和来源 等),参数没有过滤和验证。因此,恶意攻击者可以任意控制这些参数的值,用户发送inject攻击。
4. 邮件注入示范
为了使用PHP作为邮件发送代理,我们需要对PHP.INI进行简单的配置:
[mail&function]&
;&For&Win32&only.&
;&http://php.net/smtp&
SMTP&=&smtp.qq.com&
;&http://php.net/smtp-port&
smtp_port&=&25&
出于演示目的,我们将使用前面的带漏洞的代码。此外,我们将提交下列值作为发送邮件的参数:
mail(&&,&&Call&me&urgent&,&&Hi,nPlease&call&me&ASAP.nBye&,&&From:&n&)&
表单发送的HTTP数据包:
从攻击者的角度来看,有许多额外的字段,可以被注入在邮件标题。更多信息见RFC 822。例如,CC(抄送)或者BCC(密送)允许攻击者插入更多的消息。
但要注意的是,我们在添加一个新的参数之前,我们必须增加一个换行符分隔每个字段。换行符的16进制值为&0x0A&。下面是一个demo code。
1) Cc/Bcc注入
在发送者字段(sender)后注入Cc和Bcc参数
From:%0ACc:%0ABcc:
所以现在,消息将被发送到recipient和recipient1账户。
2) 参数注射
From:%0ATo:
现在消息将被发送到原来的收件人和攻击者帐户。注意,这里的攻击者的账户是我们通过注入额外传入的。
3) 邮件主题注入
From:%0ASubject:This&s%20Fake%20Subject
攻击者注入的假的主题subject将被添加到原来的主题中并且在某些情况下将取代原本的主题subject。这取决于邮件服务行为。即代码编写的容错性,当参数中出现两个subject的时候代码是选择丢弃还是后者覆盖。
4) 改变消息的主体body
要注意SMTP的Mail格式,消息主题和头部Header之间有两个换行符(和HTTP是一样的)。
From:%0A%0AMy%20New%20%0Fake%20Message.
假消息将被添加到原始消息中。
5. 实战演示
这里提示一下,直接配置php.ini原生的email功能可能不太好用,配置起来也麻烦,建议采用一些第三方的Email(WP就挺不错的)进行发送,这个模块已经把相关的交互和HTTP数据包的构造封装好了。
附带上一些实验截图:
1) 正常发送
2) Cc/Bcc注入
在From字段添加Inject Payload
发送邮件后,增加了抄送的功能:
3) 邮件主题注入
我们在from的参数加添加subject字段:
接收邮件后:
可以看到,原本的subject被注入语句覆盖了一部分内容,但是具体是覆盖还是附加和具体的PHP代码编写逻辑有关,因为现在CMS对Email发送的普通做法就是利用PHP进行HTTP/HTTPS数据包的构造,先在本地构造好数据包后,再想服务器发送。
所以不同的系统对email注入的效果会有所不同。
4) 改变消息的主体body
这里要注意的的,SMTP区分消息头部和消息主题是依据%0A%0A双换行符决定的。
发送邮件后,我们发现消息的消息体已经被修改了。
以上就是我在本地的PHP环境中模拟实验的结果,因为环境和程序代码处理逻辑的差异,可能在不同的环境下实验会有差异,我的经验是根据不同的PHP CMS系统的Email源代码进行分析,理清发送Email数据包的代码逻辑,有针对性的进行email 注入。
6. 解决方案
1. 永远不要信任用户的输入字段。所有用户输入应该被认为是不可信的和潜在的恶意。应用程序不受信任的输入过程可能会变得容易受到诸如缓冲区溢出攻击、SQL注入,OS指令注入、拒绝服务和电子邮件注入。
2. 使用正则表达式来过滤用用户提交的数据。例如,我们可以在输入字符串中搜索(r 或 n)。
3. 使用外部和库,提供防范这个问题像 ZEND mail、PEAR mail和swift mailer。
4. ModSecurity可以阻止服务器级别的电子邮件注入。利用ModSecurity,我们可以检测通过POST或GET提交的CC, BCC或目的地址,并且拒绝任何包含这些字母请求。基于HBase的冠字号查询系统1--理论部分
1. 软件版本和部署
maven:3.3.9,jdk:1.7 ,Struts2:2.3.24.1,hibernate:4.3.6,spring:4.2.5,MySQL:5.1.34,Junit:4,Myeclipse:2014;
Hadoop2.6.4,HBase1.1.2
下载:https://github.com/fansy1990/ssh_v3/releases
数据下载:http://download.csdn.net/detail/fansy 或
2. 背景&思路
目前针对钞票识别,一般都是使用看、摸、听、测四种方式,这里使用一种比较客观的方式类进行识别。 建设冠字号管理查询,以冠字号查询为手段,有效解决银行对外误付假币的问题。从源头解决伪钞问题。
本系统就是使用客观的方法来验证伪钞。本系统采用的方案是基于冠字号的,每张人民币的冠字号是唯一的,如果有一个大表可以把所有的人民币以及人民币对应的操作(在什么时间、什么地点存入或获取)记录下来,这样在进行存取时就可以根据冠字号先查询一下,看当前冠字号对应的纸币在大表中的保存的情况,这样就可以确定当前冠字号对应的纸币是否是伪钞了(这里假设在大表中的所有冠字号对应的钞票都是真钞)。
下面对应存储场景:
最近状态(表中有无)
有(此时没有无状态)
目前,基于传统存储数据一般在千万级别(受限于查询等性能),但是如果要存储所有钞票的信息以及其被存储或获取的记录信息,那么传统数据库肯定是不能胜任的。所以本系统是基于HBase的。
3. 功能指标
? 存储万级用户信息;
? 存储百万级别钞票信息;
? 支持前端业务每秒500+实时查询请求;
? 数据存储和计算能够可扩展;
? 提供统一接口,支持前端相关查询业务;
说明: 其中前两条,万级用户信息和百万级钞票信息是根据数据确定的,这里可以根据数据以及集群的大小进行调整(如果集群够大,存储信息也可以很大);
冠字号查询系统包括下面5层:
? 数据层:包括基础数据MySQL、文档、Web数据等;
? 数据处理层:主要是数据的加载,包括MR加载方式、 API加载模式、Sqoop加载模式等;
? 数据存储层:主要是HBase存储,包括钞票的所有信息以及用户信息等;
? 数据服务层:主要是对外提供查询、存储等接口服务;
? 数据应用层:存取钞系统,在存钞时设计到伪钞识别;其他应用系统;
5.1原始数据:
冠字号存储记录(冠字号,表中是否有该冠字号(0表示没有,1表示有),存储或取时间,存储或取所在银行编号,用户id):
用户信息表(用户Id,名字,出生日期,性别,地址,手机号,绑定银行编号):
5.2冠字号记录
对数据进过初步探索,发现冠字号规律如下:
AAA[A~Z][]
AAB[A~Z][]
如果集群有四个节点,设置region初始为4,那么三个split点为:AAAM9999,AAAZ9999,AABM9999;
假设每个用户每天进行10次操作,如果要保存100天数据,那么设置版本数为1000,则建表语句如下:
create 'records',{NAME=&'info',VERSIONS=&1000},SPLITS =&['AAAM9999','AAAZ9999','AABM9999']
表结构描述如下:
字段值举例
表主键(钞票冠字号)
long型(可以存储用户操作的时间)
who、when、where做了哪些操作
如果用户是存储行为,那么在行为结束后,该值为1
存取钞银行
5.3用户信息
对数据进过初步探索,发现用户信息规律如下:
~92]XXXX[]
如果集群有四个节点,设置region初始为4,那么三个split点为:XXXX1991XXXX1992XXXX0000;
则建表语句如下:
create 'user',{NAME=&'info'},SPLITS =&['XXXX0000','XXXX0000','XXXX0000']
表结构描述如下:
字段值举例
用户主键(身份证号)
用户注册银行
用户出生年月
6. 数据加载
系统在投入使用的时候,已经存在历史数据,需要把历史数据批量导入到系统中;在人民币首次发行时,也需要批量导入系统中。这里的导入直接使用MR导入。
MR设计成一个通用的数据从HDFS导入HBase的MR:
6.1 主类:
package ssh.
import org.apache.hadoop.conf.C
import org.apache.hadoop.conf.C
import org.apache.hadoop.fs.P
import org.apache.hadoop.hbase.TableN
import org.apache.hadoop.hbase.mapreduce.TableMapReduceU
import org.apache.hadoop.mapreduce.J
import org.apache.hadoop.mapreduce.lib.input.FileInputF
import org.apache.hadoop.mapreduce.lib.input.TextInputF
import org.apache.hadoop.util.T
import ssh.util.HadoopU
* Job Driver驱动类
* @author fansy
public class ImportToHBase extends Configured implements Tool {
public static final String SPLITTER = &SPLITTER&;
public static final String COLSFAMILY = &COLSFAMILY&;
public static final String DATEFORMAT = &DATEFORMAT&;
public int run(String[] args) throws Exception {
if (args.length != 5) {
System.err
.println(&Usage:\n demo.job.ImportToHBase
return -1;
if (args[3] == null || args[3].length() & 1) {
System.err.println(&column family can't be null!&);
return -1;
Configuration conf = getConf();
conf.set(SPLITTER, args[2]);
conf.set(COLSFAMILY, args[3]);
conf.set(DATEFORMAT, args[4]);
TableName tableName = TableName.valueOf(args[1]);
Path inputDir = new Path(args[0]);
String jobName = &Import to & + tableName.getNameAsString();
Job job = Job.getInstance(conf, jobName);
job.setJarByClass(ImportMapper.class);
FileInputFormat.setInputPaths(job, inputDir);
job.setInputFormatClass(TextInputFormat.class);
job.setMapperClass(ImportMapper.class);
TableMapReduceUtil.initTableReducerJob(tableName.getNameAsString(),
null, job);
job.setNumReduceTasks(0);
HadoopUtils.setCurrJob(job);// 设置外部静态Job
return job.waitForCompletion(true) ? 0 : 1;
主类的run方法中使用的是传统的MR导入HBase的代码,只是设置了额外的参数,这里主类参数意思解释如下:
input: HDFS输入数据路径;
splitter : 输入数据字段分隔符;
tableName : 表名;
: 列描述, rk代表rowkey以及rowkey所在列、ts代表timestamp及其所在列;示例数据说明原始数据,第一列为rowkey,第二列为timestamp所在列,第三列属于列簇col1,同时列名为q1,第4列属于列簇col2,同时列名为q1;
date_format : timestamp日期格式,如果列描述中没有ts那么就代表原始数据中没有timestamp,则此参数没有意义;
6.2 Mapper:
package ssh.
import java.io.IOE
import java.text.ParseE
import java.text.SimpleDateF
import java.util.ArrayL
import org.apache.hadoop.hbase.client.P
import org.apache.hadoop.hbase.io.ImmutableBytesW
import org.apache.hadoop.hbase.util.B
import org.apache.hadoop.io.LongW
import org.apache.hadoop.io.T
import org.apache.hadoop.mapreduce.M
* Mapper类,接收HDFS数据,写入到HBase表中
* @author fansy
public class ImportMapper extends Mapper{
private static final String COMMA = &,&;
private static final String COLON=&:&;
private String splitter =
// private String colsStr =
private int rkIndex =0; // rowkey 下标
private int tsIndex =1; // timestamp下标
private boolean hasTs = // 原始数据是否有timestamp
private SimpleDateFormat sf =
private ArrayList colsFamily=
private Put put =
ImmutableBytesWritable rowkey = new ImmutableBytesWritable();
protected void setup(Mapper.Context context)
throws IOException, InterruptedException {
splitter = context.getConfiguration().get(ImportToHBase.SPLITTER,&,&);
String colsStr = context.getConfiguration().get(ImportToHBase.COLSFAMILY,null);
sf = context.getConfiguration().get(ImportToHBase.DATEFORMAT,null)==null
? new SimpleDateFormat(&yyyy-MM-dd HH:mm&)
:new SimpleDateFormat(context.getConfiguration().get(ImportToHBase.DATEFORMAT));
String[] cols = colsStr.split(COMMA, -1);
colsFamily =new ArrayList&&();
for(int i=0;i& cols.i++){
if(&rk&.equals(cols[i])){
colsFamily.add(null);
if(&ts&.equals(cols[i])){
colsFamily.add(null);
hasTs = // 原始数据包括ts
colsFamily.add(getCol(cols[i]));
* 获取 family:qualifier byte数组
* @param col
private byte[][] getCol(String col) {
byte[][] fam_qua = new byte[2][];
String[] fam_quaStr = col.split(COLON, -1);
fam_qua[0]=
Bytes.toBytes(fam_quaStr[0]);
fam_qua[1]=
Bytes.toBytes(fam_quaStr[1]);
return fam_
protected void map(LongWritable key, Text value,
Mapper.Context context)
throws IOException, InterruptedException {
String[] words = value.toString().split(splitter, -1);
if(words.length!=colsFamily.size()){
System.out.println(&line:&+value.toString()+& does not compatible!&);
rowkey.set(getRowKey(words[rkIndex]));
put = getValue(words,colsFamily,rowkey.copyBytes());
context.write(rowkey, put);
* 获取Put值
* @param words
* @param colsFamily
* @param bs
private Put getValue(String[] words, ArrayList colsFamily, byte[] bs) {
Put put = new Put(bs);
for(int i=0;iMapper是整个流程的核心,主要负责进行数据解析、并从HDFS导入到HBase表中的工作,其各个部分功能如下:? setup():获取输入数据字段分隔符,获取列簇、列名,获取rowkey列标,获取ts格式及列标(如果没有的话,就按照插入数据的时间设置);? map():解析、过滤并提取数据(需要的字段数据),生成Put对象,写入HBase;&6.3 针对records,user MR导入:&只需要进行拼凑参数,然后直接调用即可。
7. 实时数据加载
使用Java API来操作HBase数据库,完成实时HBase数据库更新,包括冠字号查询、存取款等功能。

我要回帖

更多关于 手机型号 的文章

 

随机推荐