ThinkPHP5的where函数

0x00 关于thinkphp5的where函数 年前公司委托别的公司开发一个网站,使用的是ThinkPHP 5.0.13,存在一个注入漏洞,分析后发现是因为tp5中的where函数使用不当,tp5中where这个函数可以接收字符串和数组这两种类型的参数来进行查询,而在用字符串这种传递方式时,如果使用不当的话就可能会出现sql注入。 0x01 示例代码 tp5/application/home/controller/Index.php <?php namespace app\home\controller; use think\Db; class Index { //http://127.0.0.1/Source/tp5/home/index/testdb/id/1 public function testDb() { // 调用 tp5/thinkphp/library/think/Db.php 的 connect() 函数 初始化数据库,并取得数据库类实例 $msg = db('msg'); $id = input('param.id',1); //不存在id的话默认为1 //在Db.php中use think\db\Query; $msg->where()则调用了Query.php中的where函数进入查询流程 $result = $msg->where("id=".$id)->select(); // $result = $msg->where(['id'=>$id])->select(); echo '<br/><hr/>执行的sql语句:'; echo $msg->getLastSql(); echo '<br/>最终得到的结果:'; echo var_dump($result); } } where函数接收字符串和数组时,访问http://127.0.0.1/Source/tp5/home/index/testdb/id/1执行的SQL语句分别如下: SELECT * FROM `msg` WHERE ( id=1 ) SELECT * FROM `msg` WHERE `id` = 1 前者存在注入,当payload为: ) and 1=1 and (1)=(1时判断返回如下: 主要调用文件及函数顺序如下:


打包下载php文件

0x00 代码如下 <?php function addFileToZip($zip,$zipname,$path){ $handler = opendir($path); while(($filename = readdir($handler))!==false) { if($filename != "." && $filename != ".." && $filename!= $zipname){ if (is_dir($path."/".$filename)) { //如果读取的某个对象是文件夹,则递归 addFileToZip($zip,$zipname,$path."/".$filename); } else { $zip->addFile($path."/".$filename); } } } @closedir($path); } function tar($zipname,$path) { $zip = new ZipArchive(); //使用本类,linux需开启zlib,windows需取消php_zip.dll前的注释 if ($zip->open($zipname, ZipArchive::OVERWRITE) === TRUE) { addFileToZip($zip,$zipname,$path);$zip->close(); } else { exit('Unable to open file, or file creation failed!'); } } function download($zipname) { if(!file_exists($zipname)){ exit("Zip file does not exist!


PHP安全配置

0x00 PHP的配置 PHP的配置文件为php.ini,其中有些项配置不当的话就会造成一些安全问题 0x01 远程文件包含 涉及配置项 allow_url_include 配置为On时允许进行远程文件包含 allow_url_fopen 配置为On时允许使用函数fopen、file_put_contents 配置方案 alllow_url_include = Off allow_url_fopen = Off 0x02 关闭错误回显 涉及配置项 display_errors 配置为On时会显示错误信息 配置方案 display_errors = Off log_errors = On error_log = /var/log/php_error.log 0x03 隐藏php版本 涉及配置项 expose_php 为Off时会隐藏php版本 配置方案 expose_php = Off 0x04 魔术引号 涉及配置项 magic_quotes_gpc 过滤get、post、cookie的单引号、双引号、反斜杠、空字符,但不过滤$_SERVER magic_quotes_runtime 对文件或数据库中取出的数据进行过滤,可防止二次注入 配置方案 做逻辑判断时需要去掉反斜杠,所以用全局过滤框架做过滤吧 0x05 安全模式 涉及配置项 safe_mode 开启后安全系数提升,但会限制函数使用权限和操作目录文件权限等 配置方案 在安全模式下可以使用safe_mode_include_dir = /var/www/common来排除某些文件 0x06 目录权限控制 涉及配置项 open_basedir 开启后可将用户访问范围限定,可防止跨站,但会影响性能 配置方案 open_basedir = /var/www/web1/:/var/www/web2/ (后面的斜杠不能少) 0x07 禁止函数 涉及配置项 disable_functions 禁止某些命令执行函数和文件操作函数的使用 配置方案 disable_functions = system,passthru,exec,shell_exec,popen,pcntl_exec, proc_open,chdir,chroot,getcwd,readdir,mkdir,copy,file_get_contents, 0x08 注册全局变量 涉及配置项 register_globals 值为On是会开启全局注册变量功能 配置方案 register_globals = Off


CGI与FastCGI与PHP-FPM

0x01 CGI协议 中间件在收到请求时会去找php解析器处理,cgi是规定了要传递哪些数据(比如url、header、post数据等)的协议 0x02 FastCGI 服务端收到请求时会启动对应的cgi程序(如php-cgi),即php的解析器,php解析器会解析php.ini文件、初始化执行环境,然后执行请求,每次都是这样,性能比较低 fastcgi是cgi的升级版,它会启动一个master解析php.ini、初始化执行环节,然后启动多个worker直接依次处理多个web server的连接,不用每次都解析php.ini等 0x03 FastCGI工作流程 一般情况下,FastCGI的整个工作流程是这样的: Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module) FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待WebServer的连接。 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。 Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。 FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。在CGI模式中,php-cgi在此便退出了。 0x04 PHP-FPM php-fpm就是fastcgi的实现,是一个php fastcgi进程管理器 php-fpm在php5.2之后默认添加 千万不要把fastcgi端口对公网暴露


PHP之封装MySQL类

0x00 config.inc.php内容如下 <?php return array( 'DB_HOST' => '192.168.188.134', 'DB_NAME' => 'scoreboard', 'DB_USER' => 'score', 'DB_PASS' => '123456', 'DB_CHARSET' => 'utf8', 'IS_LOG' => 1,//开启日志 'LOGFILEPATH' => '../log.txt'//日志路径 ); /* $database = require('./config.php'); echo $database['DB_TYPE']; //输出'DB_TYPE' */ ?> 0x01 表设计如下 create database scoreboard; use scoreboard; drop table if exists users; create table users( id int not null auto_increment primary key, gid int not null default 'xiaoming' comment '组id', username varchar(20) not null default 'xiaoming' comment '用户名', password varchar(32) not null default '123456' comment '密码', sex varchar(2) not null default '0' comment '性别', totalscore int not null default '0' comment '个人总积分' ); drop table if exists share; create table share( id int not null auto_increment primary key, uid int not null, content varchar(1024) not null default 'content' comment '分享内容', comment varchar(1024) comment '点评', date varchar(15) not null default '20150101' comment '分享日期' ); drop table if exists score; create table score( id int not null auto_increment primary key, uid int not null default '0' comment '用户id', score int not null default '0' comment '用户单次积分', ); grant all privileges on scoreboard.


PHP之MySQL常用函数

0x00 处理函数 mysql_connect(server,user,pwd,newlink,clientflag) 连接服务器的函数,成功则返回MySQL标识,失败则返回FALSE mysql_select_db(database,connection) 选择数据库的函数,成功则返回true,失败则返回false mysql_query(query,connection) 执行一条查询,返回一个资源标识符(结果集),如果查询执行不正确则返回FALSE mysql_num_rows(data)和mysql_num_fields(data) 函数分别返回结果集中行和列的数目(禁对SELECT语句有效),结果集从 mysql_query()的调用中得到 mysql_fetch_assoc(data) 从结果集中取得一行作为关联数组,若没有更多行则返回false mysql_fetch_row(data) 从结果集中取得一行作为索引数组,若没有更多行则返回false mysql_error(connection) 返回上一个MySQL函数的错误文本,如果没有出错则返回”(空字符串) mysql_affected_rows(link_identifier) 返回前一次MySQL操作(增删改)所影响的记录行数,失败则返回-1 mysql_insert_id(connection) 返回上一步INSERT操作产生的 ID。如果上一查询没有产生AUTO_INCREMENT的ID,则mysql_insert_id()返回 0。 mysql_data_seek(data,row) 结果集data从mysql_query()的调用中得到,行指针移动到指定的行号,接着调用 mysql_fetch_row() 将返回那一行。如果成功则返回 true,失败则返回 false 0x01 例子 <?php $server = "127.0.0.1"; $dbname = "massage"; $user = "msg"; $pass = "123456" $conn = mysql_connect($server,$user,$pass) or die('连接服务器失败:'.mysql_error()); mysql_query("set names 'utf8'");//设置数据库输出编码 mysql_select_db($dbname,$conn) or die(mysql_error($conn)); //选择数据库 $sql = "select username,password from user"; //构造sql语句 $result = mysql_query($sql); //执行sql语句,返回结果集 $num = mysql_num_rows($result);//返回执行结果的行数 echo "<br />结果的行数:{$num}<br />"; while ($row = mysql_fetch_assoc($result)) { echo $row[id].


PHP之上传与下载

0x00 上传 客户端设置 客户端使用form表单上传文件,在form表单中必须指明enctype和method属性的值 <html> <head> <title>post</title> </head> <body> <form action="xx.php" mothod="post" enctype="multipart/form-data"> <input type="file" value="myfile" /><br /> <input type="submit" value="提交" /> </form> </body> </html> 服务端设置 php.ini: file_uploads = On //默认允许HTTP文件上传,此选项不能设置为OFF upload_tmp_dir= //文件上传时存放文件的临时目录 upload_max_filesize = 20M //设定单个文件上传的大小,必须小于post_max_size post_max_size = 19M //允许POST表单的数据最大大小 $_FILES: $_FILES['upload_file']['name'] //带扩展名的原始文件名 $_FILES['upload_file']['size'] //文件大小 $_FILES['upload_file']['tmp_name'] //临时文件名 $_FILES['upload_file']['error'] //上传文件时的错误信息 $_FILES['upload_file']['type'] //上传文件的类型 //type是上传文件时原始信息里的content_type,即MIME,有image/gig、text/html等 //error一般有5中类型: //0 上传成功 //1 文件大小超过了upload_max_filesize //2 文件大小超过了表单总MAX_FILE_SIZE设定的值 //3 只有部分被上传 //4 没有上传任何文件 服务端上传步骤


PHP之目录与文件

0x00 目录的操作 <?php $path = "/var/www/html/php/dir.php"; echo dirname($path)."<br />"; //返回上级路径 echo basename($path)."<br />"; //返回文件名部分 print_r(pathinfo($path)); //返回包含path信息的数组 echo "<br /><br />"; //readdir()从目录句柄读取条目,返回目录中的文件名,指针依次向后移动 $path = "D:/phpStudy/WWW/php"; $dh = opendir($path); while (false !== ($filename=readdir($dh))) { echo $filename."<br />"; } rewinddir($dh); //指针复位 echo readdir($dh); closedir($dh); mkdir("./aaa");//创建文件夹aaa rmdir("./aaa");//删除文件夹aaa file_put_contents("aa.php", "");//创建文件aa.php unlink("./aa.php");//删除文件aa.php ?> 0x01 文件的读写 fopen(filename,mode)和fclose(filename,mode) 例子: <?php $file = fopen("test.txt","r"); $file = fopen("/home/test/test.txt","r"); $file = fopen("/home/test/test.gif","wb"); $file = fopen("http://www.example.com/","r"); $file = fopen("ftp://user:password@example.


PHP之字符串

0x00 特点 字符串可以使用数组的处理函数操作,但并不是真正的数组 双引号中的变量用{}括起来,因为字符串中若遇到$符号,解析器会尽可能多的获取后面的字符以组成一个合法的变量名 <?php $lamp = array('os' => 'Linux', 'webserver' => 'Apache', 'db' => 'Mysql', 'language' => 'PHP'); echo "A OS is $lamp[os]."; // ok echo "A OS is $lamp['os']."; // false echo "A OS is {$lamp['os']}."; //ok echo "A OS is {$lamp[os]}."; // ok echo "This square is $square->width meters broad."; //ok echo "This square is $square->width meters broad."; //ok echo "This square is $square->width meters broad.


PHP之面向对象

0x00 面向对象 面向对象概念 面向对象是达到了软件工程的三个目标:重用性、灵活性和扩展性,使其编程的代码更加简洁、更易于维护、并且具有更强的可重用性。 类和对象的关系 在面向对象的编程语言中,类是一个对立的程序单位,而对象的抽象就是类。类描述了一组有相同特性(属性)和相同行为(方法)的对象。开发时要先抽象类再用该类去创建对象。而我们的程序中直接使用的是对象而不是类。 什么是类 在面向对象的编程语言中,类是一个对立的程序单位,是具有相同属性和服务的一组对象的集合。它为属于该类的所有对象提供了同意的抽象描述,其内部包括成员属性和服务的方法两个部分。 什么是对象 在客观世界里,所有的事物都是由对象和对象之间的联系组成的。对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位,一个对象由一组属性和有权对这些属性进行操作的一组服务的封装体。 0x01 类的声明 类名和变量名还有函数名的命名规则类似,都遵循PHP中定义名称的命名规则。 若类名由多个单词组成,习惯上每个单词的首字母要大写 类中成员可分为属性和方法 属性为静态描述,方法为动态描述 在类中声明成员属性时,变量前面一定要有关键字,如:public、private、static等 若不需要有特定意义的修饰,则使用var关键字 格式: [一些修饰类的关键字] class 类名 { 类中成员; } Class Person { 成员属性: 姓名、性别、年龄、身高、体重、电话、住址等 成员方法: 说话、学习、走路、吃饭、开车、使用手机等 } 例子: <?php class Person { var $name; var $age; var $sex; function say() { echo "人在说话"; } function run() { echo "人在走路"; } } ?



可以返回顶部